JS: Why does SanitizingRegExpTest treat /^...$/m as a whole-string check?
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Accessibilité débutants
- 45/100
- Type d'issue
- Bug
- Clarté
- Plutôt claire
- Activité
- Active
- Stack technique
- javascript
- Domaine
- security
Piste de recherche
Start with javascript/ql/lib/semmle/javascript/Regexp.qll, especially isFullyAnchoredTerm, isMultiline, and maybeMultiline, then trace how isGenericRegExpSanitizer feeds SanitizingRegExpTest in javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll. Check the relevant JavaScript security query tests for anchored regular expressions with and without the m flag. Done means multiline anchored checks no longer suppress taint findings while non-multiline anchored checks retain their current behavior.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Description of the issue
JavaScript taint-tracking queries treat a test against a regular expression anchored with ^ and $ as a check of the whole string, also when the regular expression has the m flag. I'm wondering whether this is intended, because with m, ^ and $ also match at line boundaries, so any string that contains one matching line passes the check: /^[\w.-]+$/m.test("x\ntouch /tmp/marker") is true.
Affected sanitizer
SanitizingRegExpTest, which is "considered to be a sanitizer for all configurations", uses RegExp::isGenericRegExpSanitizer for re.test(x), re.exec(x), x.match(re) and x.matchAll(re). For the true outcome, that predicate only requires isFullyAnchoredTerm, which looks for a leading RegExpCaret and a trailing RegExpDollar. The flags of the regular expression are not consulted, although the same module has isMultiline and maybeMultiline.
Steps to reproduce
const cp = require("child_process");
const app = require("express")();
app.get("/a", (req, res) => {
const dir = req.query.dir;
if (/^[\w.-]+$/m.test(dir)) {
cp.exec("ls " + dir); // not reported
}
res.send("ok");
});
app.get("/b", (req, res) => {
const dir = req.query.dir;
if (/^[\w.-]+$/.test(dir)) {
cp.exec("ls " + dir); // not reported (correct: no newline can pass)
}
res.send("ok");
});
app.get("/c", (req, res) => {
const dir = req.query.dir;
cp.exec("ls " + dir); // reported
res.send("ok");
});
app.get("/d", (req, res) => {
const name = req.query.name;
if (/^\w+$/m.test(name)) {
res.send("<p>Hello " + name + "</p>"); // not reported
} else {
res.send("bad name");
}
});
app.get("/e", (req, res) => {
res.send("<p>Hello " + req.query.name + "</p>"); // reported
});
app.listen(3000);
With javascript-security-extended.qls, only /c (js/command-line-injection) and /e (js/reflected-xss) are reported. /a and /d are not, although at runtime their checks do not restrict the input:
dir = "x\ntouch /tmp/marker"(sent as?dir=x%0Atouch%20/tmp/marker) passes the check in/a, andcp.exec("ls x\ntouch /tmp/marker")runstouch /tmp/markeras a second command. The file is created.name = "x\n<script>alert(1)</script>"passes the check in/d, and the script element is sent in the response.
Without the m flag (/b), the check does restrict the input, so not reporting it is right.
The same mistake has led to real vulnerabilities, e.g. GHSA-3px3-54cx-rmw9 (CVE-2026-83609, @xmldom/xmldom 0.9.0–0.9.11), where an anchored validation regular expression was compiled with the m flag and a name with an embedded line terminator passed the check.
Question
Is it intended that the m flag is ignored here? Would it be reasonable to stop treating an anchored regular expression as a whole-string check when it has the m flag?
Environment
- CodeQL CLI 2.27.2 (
codeql/javascript-queries2.4.7) - CodeQL repository commit for the links above:
781e068896eb7a1a104f1378e8f3f68a1074a015(the files are unchanged since 2.27.2) - Node.js v24.18.0 on Linux/amd64
- Langage dominant
- CodeQL
- Étoiles
- 10.2k
- Forks
- 2.1k
- Merge moyen
- 2 j 18 h
- PR mergées (30 j)
- 142
Préparer son environnement
Lance le conteneur de développement du projet dans votre navigateur, avec votre propre compte GitHub.
- Aucun Dockerfile ni fichier Docker Compose
- Aucun modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de github/codeql
-
false-positive javascript
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
github/codeql#22632 · 3 commentaires · 1 réaction · 2 personnes assignées ·
Les mainteneurs répondent en général sous 1 jour
-
Add AlertSuppression.ql for Rust (inline // codeql[...] suppression)Peut-être pris @cnuss l’a pris il y a 202 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
github/codeql#21637 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
false-positive
Difficulté 2/5 1-3 heures Accessibilité débutants 70/100
github/codeql#21076 · 3 commentaires · 3 réactions ·
Les mainteneurs répondent en général sous 1 jour
-
false-positive
Difficulté 4/5 3-5 jours Accessibilité débutants 48/100
Les mainteneurs répondent en général sous 1 jour
-
question
Difficulté 4/5 3-5 jours Accessibilité débutants 52/100
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de github/codeql
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
mvanhorn/cli-printing-press#5142 ·
Les mainteneurs répondent en général sous 1 jour
-
blocklist addition
Difficulté 1/5 Moins d'une heure Accessibilité débutants 66/100
MetaMask/eth-phishing-detect#304596 ·
Les mainteneurs répondent en général sous 1 jour
-
bug 🐛
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
netalertx/NetAlertX#1856 · 1 réaction ·
Les mainteneurs répondent en général sous 1 jour
-
netsuite-client-credentials: NetSuite rejects the JWT assertion (needs alg PS256 and a scope claim)Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 73/100
NangoHQ/nango#7997 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
bug good first issue
Difficulté 2/5 1-3 heures Accessibilité débutants 80/100
yunaremaia/mcp-guard#120 ·
Les mainteneurs répondent en général sous 1 jour