Structural taint engine: argument-taint (call args / binary-expr operands)

ober

bc6a4fd41e1544500658526d757c3b80095a80e9

diff --git a/lib/semgrep/scan.sls b/lib/semgrep/scan.sls
index b3fafb3..d3cfe39 100644
--- a/lib/semgrep/scan.sls
+++ b/lib/semgrep/scan.sls
@@ -31826,6 +31826,36 @@
                         arg-text
                         (metavariable-binding-text (cdr entry))))
                     (finding-metavars source))))))
+  (def (simple-identifier-text? s)
+       (let* ([t (string-trim s)] [len (string-length t)])
+         (and (> len 0)
+              (let loop ([i 0])
+                (or (>= i len)
+                    (and (identifier-char? (string-ref t i))
+                         (loop (+ i 1))))))))
+  (def (original-bare-variable-source?
+         source-state
+         source-text)
+       (let ([finding (taint-state-finding source-state)])
+         (and finding
+              (not (taint-state-side-effect? source-state))
+              (equal? (taint-state-origin source-state) finding)
+              (simple-identifier-text?
+                (finding-text finding source-text)))))
+  (def (source-token-in-sink-arg?
+         source-state
+         sink
+         source-text)
+       (and (original-bare-variable-source?
+              source-state
+              source-text)
+            (let ([arg-text (direct-call-argument-text
+                              sink
+                              source-text)]
+                  [st (finding-text
+                        (taint-state-finding source-state)
+                        source-text)])
+              (and arg-text (string-contains-token? arg-text st)))))
   (def (line-indent line)
        (let ([len (string-length line)])
          (let loop ([i 0])
@@ -31912,6 +31942,10 @@
                             source
                             sink
                             source-text)
+                          (source-token-in-sink-arg?
+                            source-state
+                            sink
+                            source-text)
                           (and (taint-state-token? source-state)
                                (source-token-in-sink/except?
                                  source
@@ -32929,6 +32963,7 @@
                          sink
                          source-text))
                   (source-base-of-sink-arg? source sink source-text)
+                  (source-token-in-sink-arg? source-state sink source-text)
                   (and (finding-range-contains? sink source)
                        (not (finding-range-equal? sink source))
                        (echo-or-print-statement-sink? sink source-text)
@@ -33168,7 +33203,13 @@
                         (metavariable-binding-text from-binding))
                       (field-source-taints-base-text?
                         (metavariable-binding-text from-binding)
-                        (finding-text source-finding source)))))))
+                        (finding-text source-finding source))
+                      (and (original-bare-variable-source?
+                             source-state
+                             source)
+                           (string-contains-token?
+                             (metavariable-binding-text from-binding)
+                             (finding-text source-finding source))))))))
   (def (propagator-blocked-by-sanitizer?
          source-state
          from-finding
diff --git a/src/semgrep/scan.ss b/src/semgrep/scan.ss
index d403504..77fa992 100644
--- a/src/semgrep/scan.ss
+++ b/src/semgrep/scan.ss
@@ -31775,6 +31775,28 @@
                        (metavariable-binding-text (cdr entry))))
                    (finding-metavars source))))))
 
+(def (simple-identifier-text? s)
+  (let* ([t (string-trim s)]
+         [len (string-length t)])
+    (and (> len 0)
+         (let loop ([i 0])
+           (or (>= i len)
+               (and (identifier-char? (string-ref t i))
+                    (loop (+ i 1))))))))
+
+(def (original-bare-variable-source? source-state source-text)
+  (let ([finding (taint-state-finding source-state)])
+    (and finding
+         (not (taint-state-side-effect? source-state))
+         (equal? (taint-state-origin source-state) finding)
+         (simple-identifier-text? (finding-text finding source-text)))))
+
+(def (source-token-in-sink-arg? source-state sink source-text)
+  (and (original-bare-variable-source? source-state source-text)
+       (let ([arg-text (direct-call-argument-text sink source-text)]
+             [st (finding-text (taint-state-finding source-state) source-text)])
+         (and arg-text (string-contains-token? arg-text st)))))
+
 (def (line-indent line)
   (let ([len (string-length line)])
     (let loop ([i 0])
@@ -31859,6 +31881,7 @@
                        sink
                        source-text)
                      (source-base-of-sink-arg? source sink source-text)
+                     (source-token-in-sink-arg? source-state sink source-text)
                      (and (taint-state-token? source-state)
                           (source-token-in-sink/except?
                             source
@@ -32808,6 +32831,7 @@
              (and (not (taint-state-token? source-state))
                   (direct-call-argument-source? source sink source-text))
              (source-base-of-sink-arg? source sink source-text)
+             (source-token-in-sink-arg? source-state sink source-text)
              (and (finding-range-contains? sink source)
                   (not (finding-range-equal? sink source))
                   (echo-or-print-statement-sink? sink source-text)
@@ -33084,7 +33108,15 @@
                  ;; gates above keep this name-based reach within one method.
                  (field-source-taints-base-text?
                    (metavariable-binding-text from-binding)
-                   (finding-text source-finding source)))))))
+                   (finding-text source-finding source))
+                 ;; bare variable source used inside the RHS expression
+                 ;; (`t = wrap(x)`, `w = v + x.getSomething()`): the assigned
+                 ;; target carries the taint. Restricted to original tracked
+                 ;; variables by original-bare-variable-source?.
+                 (and (original-bare-variable-source? source-state source)
+                      (string-contains-token?
+                        (metavariable-binding-text from-binding)
+                        (finding-text source-finding source))))))))
 
 (def (propagator-blocked-by-sanitizer? source-state from-finding sanitizers source)
   (any? (lambda (sanitizer-state)