@@ -13,6 +13,8 @@ import semmle.python.dataflow.new.TaintTracking
1313import PathInjectionCustomizations:: PathInjection
1414
1515/**
16+ * DEPRECATED: Use `PathInjectionFlow` module instead.
17+ *
1618 * A taint-tracking configuration for detecting "path injection" vulnerabilities.
1719 *
1820 * This configuration uses two flow states, `NotNormalized` and `NormalizedUnchecked`,
@@ -25,7 +27,7 @@ import PathInjectionCustomizations::PathInjection
2527 *
2628 * Such checks are ineffective in the `NotNormalized` state.
2729 */
28- class Configuration extends TaintTracking:: Configuration {
30+ deprecated class Configuration extends TaintTracking:: Configuration {
2931 Configuration ( ) { this = "PathInjection" }
3032
3133 override predicate isSource ( DataFlow:: Node source , DataFlow:: FlowState state ) {
@@ -74,3 +76,52 @@ class NotNormalized extends DataFlow::FlowState {
7476class NormalizedUnchecked extends DataFlow:: FlowState {
7577 NormalizedUnchecked ( ) { this = "NormalizedUnchecked" }
7678}
79+
80+ /**
81+ * This configuration uses two flow states, `NotNormalized` and `NormalizedUnchecked`,
82+ * to track the requirement that a file path must be first normalized and then checked
83+ * before it is safe to use.
84+ *
85+ * At sources, paths are assumed not normalized. At normalization points, they change
86+ * state to `NormalizedUnchecked` after which they can be made safe by an appropriate
87+ * check of the prefix.
88+ *
89+ * Such checks are ineffective in the `NotNormalized` state.
90+ */
91+ private module PathInjectionConfig implements DataFlow:: StateConfigSig {
92+ class FlowState = DataFlow:: FlowState ;
93+
94+ predicate isSource ( DataFlow:: Node source , FlowState state ) {
95+ source instanceof Source and state instanceof NotNormalized
96+ }
97+
98+ predicate isSink ( DataFlow:: Node sink , FlowState state ) {
99+ sink instanceof Sink and
100+ (
101+ state instanceof NotNormalized or
102+ state instanceof NormalizedUnchecked
103+ )
104+ }
105+
106+ predicate isBarrier ( DataFlow:: Node node ) { node instanceof Sanitizer }
107+
108+ predicate isBarrier ( DataFlow:: Node node , FlowState state ) {
109+ // Block `NotNormalized` paths here, since they change state to `NormalizedUnchecked`
110+ node instanceof Path:: PathNormalization and
111+ state instanceof NotNormalized
112+ or
113+ node instanceof Path:: SafeAccessCheck and
114+ state instanceof NormalizedUnchecked
115+ }
116+
117+ predicate isAdditionalFlowStep (
118+ DataFlow:: Node nodeFrom , FlowState stateFrom , DataFlow:: Node nodeTo , FlowState stateTo
119+ ) {
120+ nodeFrom = nodeTo .( Path:: PathNormalization ) .getPathArg ( ) and
121+ stateFrom instanceof NotNormalized and
122+ stateTo instanceof NormalizedUnchecked
123+ }
124+ }
125+
126+ /** Global taint-tracking for detecting "path injection" vulnerabilities. */
127+ module PathInjectionFlow = TaintTracking:: GlobalWithState< PathInjectionConfig > ;
0 commit comments