mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-17 03:59:28 +00:00
fix(semantic-facts): give untrusted destination the clients a Node server calls
The family census recorded this family completing 44 questions on NodeGoat, finding the open redirect, and having no way to ask about the repository's documented SSRF: needle.get on a query-string URL at app/routes/research.js:16. A thin vocabulary is a silent false negative. One data change, no query change. The declared set now covers axios, got, needle, request, superagent, unirest, undici and fetch as bare module tokens, plus http.get, http.request, https.get and https.request dotted. Bare is the documented call form of each module and covers its verb methods too, since a token matches word-bounded against the callee and axios is bounded inside axios.get; axios.get and axios.post are dropped as subsumed rather than unwanted. http and https stay dotted because their namespace also holds createServer, and a bare token would have claimed every server a repository starts. The request is now reported at app/routes/research.js:16, model_entailed, witness `req.query.url + req.query.symbol -> needle.get(url, ...)`. This family goes from one finding to two on NodeGoat, every other family is unchanged, and 299 of 299 questions still complete. Measured on that graph, needle matches exactly one call and the eleven other clients match none in first-party or vendored code, so NodeGoat shows the gap closing and cannot show those clients' noise. A control asserts both halves. A handler calling axios.get with a literal and needle.get with req.query.url reports the tainted client alone, and it reads the shipped vocabulary rather than a copy, so removing the client fails it. The CWE-601 redirect entry is untouched: a Location-header redirect is value-shaped and stays outside what this family asks. 1,411 tests pass, eleven skipped; seven Joern-gated query tests pass in the image. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
co-authored by
Claude Opus 5
parent
4e2619e248
commit
57f5a3f0dc
@@ -66,9 +66,37 @@ rule_ids = []
|
||||
|
||||
[[sink]]
|
||||
# CWE-918 / CWE-601: outbound requests and redirects to a caller-supplied destination.
|
||||
#
|
||||
# The set shipped with five clients and missed the one the measured repository calls. NodeGoat's documented
|
||||
# SSRF is `needle.get(req.query.url + req.query.symbol)` at `app/routes/research.js:16`, and the 2026-09-19
|
||||
# family census recorded this family completing 44 questions there, finding the open redirect two files away,
|
||||
# and having no way to ask about the request. A thin vocabulary is a silent false negative, so what follows is
|
||||
# the client surface a Node server actually calls.
|
||||
#
|
||||
# Bare where the module ITSELF is the request function, which is the documented call form for all of these
|
||||
# (`axios(config)`, `got(url)`, `needle('get', url)`, `request(opts)`), and which also covers every verb
|
||||
# method through it: a token is matched word-bounded against the callee, and `axios` is bounded inside
|
||||
# `axios.get`. Dotted for `http` and `https`, whose namespace also holds `createServer` -- a server is not an
|
||||
# outbound request, and the bare form would have claimed every one of them.
|
||||
#
|
||||
# Measured on NodeGoat: `needle` matches exactly the research handler's request and nothing else; none of the
|
||||
# other clients appears in that repository, in first-party code or vendored.
|
||||
id = "outbound.request"
|
||||
cwe = "CWE-918"
|
||||
calls = ["axios.get", "axios.post", "fetch", "request", "got", "http.get", "https.get"]
|
||||
calls = [
|
||||
"axios", # axios, and axios.get/.post/.put/.patch/.delete/.head/.request through it
|
||||
"got", # got
|
||||
"needle", # needle
|
||||
"request", # request / request-promise
|
||||
"superagent", # superagent
|
||||
"unirest", # unirest
|
||||
"undici", # undici, and undici.fetch/.request through it
|
||||
"fetch", # global fetch, node-fetch, cross-fetch
|
||||
"http.get",
|
||||
"http.request",
|
||||
"https.get",
|
||||
"https.request",
|
||||
]
|
||||
rule_ids = []
|
||||
|
||||
[[sink]]
|
||||
|
||||
Reference in New Issue
Block a user