Skip to content

Commit a6295e0

Browse files
misonijnikclaude
andcommitted
refactor(analyzer): Complete passThrough builder chains and package coverage
Refine the propagators added in 309492b using the engine's actual propagation semantics (no implicit this->result for unmodeled library calls; whole-object taint subsumes field reads but virtual-field taint does not satisfy a whole-object sink). Fix broken fluent chains by modeling every intermediate link, not just the endpoints: - okhttp Request.Builder: cover all builder methods, not only url/build. - spring-web RequestEntity: cover all static factories and the HeadersBuilder/BodyBuilder chain, not only get/build. - java.net.http HttpRequest.Builder: cover header/POST/PUT/method/etc., not only uri/GET/build. Broaden per-package coverage: - commons-io IOUtils: toByteArray/toCharArray/readLines. - commons-codec Base64: URL-safe and chunked encode variants. - java.util.Base64.Decoder: decode/wrap (decode direction). - spring-jdbc: substituteNamedParameters/parseSqlStatementIntoString. - spring-ldap: LdapQueryBuilder config carriers + gte/lte/not (iface+impl). - velocity: Context interface put. - groovy CompilationUnit.addSource: arg(*) to cover File/URL/SourceUnit overloads where the source is the first argument. Wrapper constructors keep whole-object arg(*)->this on purpose: their sinks consume the whole object, so a virtual-field-only taint would be a false negative. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 309492b commit a6295e0

9 files changed

Lines changed: 344 additions & 24 deletions

core/opentaint-config/config/config/jar-split/commons-codec-1.16.0.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ passThrough:
1010
copy:
1111
- from: arg(0)
1212
to: result
13+
- function: org.apache.commons.codec.binary.Base64#encodeBase64URLSafeString
14+
copy:
15+
- from: arg(0)
16+
to: result
17+
- function: org.apache.commons.codec.binary.Base64#encodeBase64URLSafe
18+
copy:
19+
- from: arg(0)
20+
to: result
21+
- function: org.apache.commons.codec.binary.Base64#encodeBase64Chunked
22+
copy:
23+
- from: arg(0)
24+
to: result
1325
- function: org.apache.commons.codec.binary.Base64#decodeBase64
1426
copy:
1527
- from: arg(0)
Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
passThrough:
2-
# Apache Commons IO: IOUtils.toString(InputStream|Reader|URL, ...) just
3-
# reads bytes/chars from its input and produces a String — taint flows
4-
# from the input source argument to the resulting String.
2+
# Apache Commons IO: IOUtils read helpers consume an input source
3+
# (InputStream | Reader | URL | byte[] | char[]) given as the first
4+
# argument and materialize its content — taint flows from that input
5+
# source to the returned String / byte[] / char[] / List<String>.
56
- function: org.apache.commons.io.IOUtils#toString
67
copy:
78
- from: arg(0)
89
to: result
10+
- function: org.apache.commons.io.IOUtils#toByteArray
11+
copy:
12+
- from: arg(0)
13+
to: result
14+
- function: org.apache.commons.io.IOUtils#toCharArray
15+
copy:
16+
- from: arg(0)
17+
to: result
18+
- function: org.apache.commons.io.IOUtils#readLines
19+
copy:
20+
- from: arg(0)
21+
to: result
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
passThrough:
2-
# Groovy compiler: CompilationUnit.addSource(name, source) — the
3-
# source text becomes part of the CompilationUnit instance that's
4-
# later compiled by .compile(), so the source-text argument taints
5-
# the unit.
2+
# Groovy compiler: CompilationUnit.addSource(...) — the source becomes
3+
# part of the CompilationUnit instance that is later run by .compile(),
4+
# so the source argument taints the unit. The source is the 2nd arg of
5+
# addSource(name, source|InputStream) but the 1st arg of the
6+
# addSource(File) / addSource(URL) / addSource(SourceUnit) overloads, so
7+
# copy from any argument into the unit.
68
- function: org.codehaus.groovy.control.CompilationUnit#addSource
79
copy:
8-
- from: arg(1)
10+
- from: arg(*)
911
to: this

core/opentaint-config/config/config/jar-split/okhttp-4.12.0.yaml

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,87 @@
11
passThrough:
2-
# OkHttp Request.Builder — `new Request.Builder().url($X).build()` chain.
3-
# `.url()` mutates the builder and returns it (taint flows arg→this and
4-
# arg→result and this→result so the chain propagates through `.build()`).
2+
# OkHttp Request.Builder fluent chain, e.g.
3+
# new Request.Builder().url($X).addHeader(..).post($BODY).build()
4+
# Library calls have no implicit this->result propagation, so every
5+
# builder method that may appear mid-chain must carry the builder taint
6+
# to its return value, or the chain breaks at the first unmodeled link.
7+
# `.url()` additionally seeds the builder from its (tainted) argument and
8+
# `.build()` carries the accumulated builder taint into the Request.
59
- function: okhttp3.Request$Builder#url
610
copy:
711
- from: arg(0)
12+
to: this
13+
- from: arg(0)
14+
to: result
15+
- from: this
16+
to: result
17+
- function: okhttp3.Request$Builder#header
18+
copy:
19+
- from: arg(*)
20+
to: this
21+
- from: this
22+
to: result
23+
- function: okhttp3.Request$Builder#addHeader
24+
copy:
25+
- from: arg(*)
26+
to: this
27+
- from: this
28+
to: result
29+
- function: okhttp3.Request$Builder#headers
30+
copy:
31+
- from: arg(0)
32+
to: this
33+
- from: this
34+
to: result
35+
- function: okhttp3.Request$Builder#post
36+
copy:
37+
- from: arg(0)
38+
to: this
39+
- from: this
40+
to: result
41+
- function: okhttp3.Request$Builder#put
42+
copy:
43+
- from: arg(0)
44+
to: this
45+
- from: this
846
to: result
47+
- function: okhttp3.Request$Builder#patch
48+
copy:
49+
- from: arg(0)
50+
to: this
51+
- from: this
52+
to: result
53+
- function: okhttp3.Request$Builder#delete
54+
copy:
955
- from: arg(0)
1056
to: this
1157
- from: this
1258
to: result
59+
- function: okhttp3.Request$Builder#method
60+
copy:
61+
- from: arg(*)
62+
to: this
63+
- from: this
64+
to: result
65+
- function: okhttp3.Request$Builder#get
66+
copy:
67+
- from: this
68+
to: result
69+
- function: okhttp3.Request$Builder#head
70+
copy:
71+
- from: this
72+
to: result
73+
- function: okhttp3.Request$Builder#removeHeader
74+
copy:
75+
- from: this
76+
to: result
77+
- function: okhttp3.Request$Builder#cacheControl
78+
copy:
79+
- from: this
80+
to: result
81+
- function: okhttp3.Request$Builder#tag
82+
copy:
83+
- from: this
84+
to: result
1385
- function: okhttp3.Request$Builder#build
1486
copy:
1587
- from: this
Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
passThrough:
22
# Spring JDBC: NamedParameterUtils.parseSqlStatement(sql) returns a
3-
# ParsedSql wrapping the original SQL, which is then passed to
4-
# (Named)JdbcTemplate query/update sinks. The parse step itself just
5-
# preserves taint into the result.
3+
# ParsedSql wrapping the original SQL; substituteNamedParameters(parsedSql|sql,
4+
# ..) then expands it back into the SQL String passed to the
5+
# (Named)JdbcTemplate query/update sinks. Each step preserves taint from
6+
# its SQL/ParsedSql input (arg(0)) into the result.
67
- function: org.springframework.jdbc.core.namedparam.NamedParameterUtils#parseSqlStatement
78
copy:
89
- from: arg(0)
910
to: result
11+
- function: org.springframework.jdbc.core.namedparam.NamedParameterUtils#substituteNamedParameters
12+
copy:
13+
- from: arg(0)
14+
to: result
15+
- function: org.springframework.jdbc.core.namedparam.NamedParameterUtils#parseSqlStatementIntoString
16+
copy:
17+
- from: arg(0)
18+
to: result

core/opentaint-config/config/config/jar-split/spring-ldap-core-2.4.1.yaml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,48 @@ passThrough:
6161
to: this
6262
- from: this
6363
to: result
64+
- function: org.springframework.ldap.query.ConditionCriteria#gte
65+
copy:
66+
- from: arg(0)
67+
to: result
68+
- from: arg(0)
69+
to: this
70+
- from: this
71+
to: result
72+
- function: org.springframework.ldap.query.ConditionCriteria#lte
73+
copy:
74+
- from: arg(0)
75+
to: result
76+
- from: arg(0)
77+
to: this
78+
- from: this
79+
to: result
80+
# `.not()` is a value-less modifier that returns the same criteria — pure
81+
# chain carrier.
82+
- function: org.springframework.ldap.query.ConditionCriteria#not
83+
copy:
84+
- from: this
85+
to: result
86+
# LdapQueryBuilder configuration methods (searchScope/countLimit/timeLimit/
87+
# attributes) return the builder unchanged; they are pure chain carriers
88+
# that may appear between base() and where(), so the builder taint must
89+
# survive across them.
90+
- function: org.springframework.ldap.query.LdapQueryBuilder#searchScope
91+
copy:
92+
- from: this
93+
to: result
94+
- function: org.springframework.ldap.query.LdapQueryBuilder#countLimit
95+
copy:
96+
- from: this
97+
to: result
98+
- function: org.springframework.ldap.query.LdapQueryBuilder#timeLimit
99+
copy:
100+
- from: this
101+
to: result
102+
- function: org.springframework.ldap.query.LdapQueryBuilder#attributes
103+
copy:
104+
- from: this
105+
to: result
64106
- function: org.springframework.ldap.query.ContainerCriteria#and
65107
copy:
66108
- from: this
@@ -93,6 +135,26 @@ passThrough:
93135
to: result
94136
- from: this
95137
to: result
138+
- function: org.springframework.ldap.query.DefaultConditionCriteria#gte
139+
copy:
140+
- from: arg(0)
141+
to: this
142+
- from: arg(0)
143+
to: result
144+
- from: this
145+
to: result
146+
- function: org.springframework.ldap.query.DefaultConditionCriteria#lte
147+
copy:
148+
- from: arg(0)
149+
to: this
150+
- from: arg(0)
151+
to: result
152+
- from: this
153+
to: result
154+
- function: org.springframework.ldap.query.DefaultConditionCriteria#not
155+
copy:
156+
- from: this
157+
to: result
96158
- function: org.springframework.ldap.query.DefaultContainerCriteria#and
97159
copy:
98160
- from: this
Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,90 @@
11
passThrough:
2-
# Spring RequestEntity static factories + builder .build() — used by
3-
# the SSRF rule's chained-builder pattern:
4-
# RequestEntity.get(URI.create($X)).build()
2+
# Spring RequestEntity fluent chain, e.g. the SSRF rule's pattern
3+
# RequestEntity.get(URI.create($X)).accept(..).header(..).build()
4+
# The static factories seed the builder from the (tainted) URI argument;
5+
# every intermediate HeadersBuilder/BodyBuilder method must carry the
6+
# builder taint to its return value (no implicit this->result exists),
7+
# and .build() carries it into the constructed RequestEntity which the
8+
# RestTemplate sink consumes whole.
9+
#
10+
# ── Static factories (URI is the first arg, except method(HttpMethod, URI)) ──
511
- function: org.springframework.http.RequestEntity#get
612
copy:
713
- from: arg(0)
814
to: result
9-
- function: org.springframework.http.RequestEntity$BodyBuilder#build
15+
- function: org.springframework.http.RequestEntity#head
16+
copy:
17+
- from: arg(0)
18+
to: result
19+
- function: org.springframework.http.RequestEntity#post
20+
copy:
21+
- from: arg(0)
22+
to: result
23+
- function: org.springframework.http.RequestEntity#put
24+
copy:
25+
- from: arg(0)
26+
to: result
27+
- function: org.springframework.http.RequestEntity#patch
28+
copy:
29+
- from: arg(0)
30+
to: result
31+
- function: org.springframework.http.RequestEntity#delete
32+
copy:
33+
- from: arg(0)
34+
to: result
35+
- function: org.springframework.http.RequestEntity#options
36+
copy:
37+
- from: arg(0)
38+
to: result
39+
- function: org.springframework.http.RequestEntity#method
40+
copy:
41+
- from: arg(*)
42+
to: result
43+
# ── HeadersBuilder chain (get/head/delete/options return this) ──
44+
- function: org.springframework.http.RequestEntity$HeadersBuilder#header
45+
copy:
46+
- from: arg(*)
47+
to: result
48+
- from: this
49+
to: result
50+
- function: org.springframework.http.RequestEntity$HeadersBuilder#headers
51+
copy:
52+
- from: arg(*)
53+
to: result
54+
- from: this
55+
to: result
56+
- function: org.springframework.http.RequestEntity$HeadersBuilder#accept
57+
copy:
58+
- from: this
59+
to: result
60+
- function: org.springframework.http.RequestEntity$HeadersBuilder#acceptCharset
61+
copy:
62+
- from: this
63+
to: result
64+
- function: org.springframework.http.RequestEntity$HeadersBuilder#ifModifiedSince
65+
copy:
66+
- from: this
67+
to: result
68+
- function: org.springframework.http.RequestEntity$HeadersBuilder#ifNoneMatch
1069
copy:
1170
- from: this
1271
to: result
1372
- function: org.springframework.http.RequestEntity$HeadersBuilder#build
1473
copy:
1574
- from: this
1675
to: result
76+
# ── BodyBuilder chain (post/put/patch/method return this) ──
77+
- function: org.springframework.http.RequestEntity$BodyBuilder#contentLength
78+
copy:
79+
- from: this
80+
to: result
81+
- function: org.springframework.http.RequestEntity$BodyBuilder#contentType
82+
copy:
83+
- from: this
84+
to: result
85+
- function: org.springframework.http.RequestEntity$BodyBuilder#body
86+
copy:
87+
- from: arg(0)
88+
to: result
89+
- from: this
90+
to: result

core/opentaint-config/config/config/jar-split/velocity-engine-core-2.3.yaml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
passThrough:
2-
# Apache Velocity: VelocityContext.put($k, $v) and the AbstractContext
3-
# super-class — taint flows from the value argument into the context
4-
# instance so a tainted value carried into the context reaches a
5-
# subsequent VelocityEngine.evaluate / Template.merge sink.
2+
# Apache Velocity: Context.put($k, $v) — the value argument is stored on
3+
# the context instance, so a tainted value carried into the context
4+
# reaches a subsequent VelocityEngine.evaluate / Template.merge sink that
5+
# consumes the whole context. Entries cover the Context interface, the
6+
# AbstractContext super-class and the concrete VelocityContext, since the
7+
# call site may be typed to any of them.
8+
- function: org.apache.velocity.context.Context#put
9+
copy:
10+
- from: arg(1)
11+
to: this
612
- function: org.apache.velocity.VelocityContext#put
713
copy:
814
- from: arg(1)

0 commit comments

Comments
 (0)