Repository navigation
Add nosql taint type and mark MongoDB sinks - #11944
Merged
Merged
Conversation
Add a new `nosql` taint type (part of the input taint class) and the corresponding `TaintedNosql` issue. Mark the appropriate MongoDB driver parameters as `nosql` sinks in the extension stub: - MongoDB\Driver\Query::__construct $filter - MongoDB\Driver\Command::__construct $document - MongoDB\Driver\BulkWrite::insert/update/delete filter and document params Co-Authored-By: Claude Opus 4.8
A plain string can never be a NoSQL query, so the nosql taint is now stripped from string-typed values (via getTaintsToRemove) - casting user input to string escapes it. Add concrete injection examples, an escape function example (@psalm-taint-escape nosql) and a minimal MongoDB\Driver\Manager stub so the documentation example is runnable. Co-Authored-By: Claude Opus 4.8
Addresses review feedback: casting an inner value to string inside an array filter (e.g. new Query(["username" => (string) $_GET["username"]])) now actually removes the nosql taint, matching the documented safe pattern. Casting to string is escapes any array-only taint via getTaintsToRemove(). Also makes the sanitize_mongo_filter example a concrete sanitizer that forces filter values to scalars. Co-Authored-By: Claude Opus 4.8
Collaborator
Author
|
bugbot run |
The previous attempt to strip nosql on every string cast rerouted all string-cast taint flows through an extra graph node, changing every taint graph / SARIF snapshot (and adding noise to unrelated html/sql flows). Instead rely on the existing sink-boundary stripping (getTaintsToRemove): a string-typed argument reaching a nosql sink is not reported. For array filters, the documented escape is a sanitizer annotated @psalm-taint-escape nosql. Docs and tests updated to match this actual behavior. Co-Authored-By: Claude Opus 4.8
This reverts commit ef39444.
…hots Restoring the string-cast nosql escaping (per review), but scoped to the taint flow graph only so the variable-use graph - and therefore unused variable/reference analysis and Psalm self-analysis - is unaffected. Casting to string now inserts a pass-through "string-cast" node on the taint graph that drops array-only taints (nosql). Updated the affected taint-path snapshots: TaintTest path strings, the taint graph dump fixture, and the SARIF report fixture. Co-Authored-By: Claude Opus 4.8
Collaborator
Author
|
bugbot run |
Adding the string-cast pass-through node only to the taint graph while rerouting the value's parent_nodes broke variable-use tracking (the chain pointed at a node absent from the variable-use graph), causing false unused variable reports and a PossiblyNullReference in self-analysis. Add it to the active data-flow graph instead: the flow chain stays intact in both modes, and removed_taints only takes effect for taint analysis. Co-Authored-By: Claude Opus 4.8
Collaborator
Author
|
bugbot run |
(int)/(float)/(bool) casts now route their value through a taint pass-through node (like (string) already did), removing every taint that cannot survive the target scalar while preserving those a scalar can still carry (e.g. sleep on numerics). This runs consistently in taint-only, variable-use-only and combined analysis modes, fixing both a false negative (sleep((int) $_GET[...]) was silently untainted) and a false positive (a value cast to a scalar inside an array no longer flags nosql/sql). Union::getTaintsToRemove() drops its isSingle() guard so literal unions such as int(0)|int(1) produced by casting a bool are handled too; isInt()/isString() already require every atomic member to match. Add TaintTest coverage for taints correctly stripped by each numeric cast and for taints that must survive (sleep through int/float, sql through string), and document that any scalar cast escapes nosql. Co-Authored-By: Claude Opus 4.8
Collaborator
Author
|
bugbot review |
…e-master
master's new CustomTaintCacheTest used 'nosql'/'nosql-json' as sample
*custom* taint names, but this branch promotes 'nosql' to a builtin
TaintKind, so getOrRegisterTaint('nosql') now returns the builtin bit
instead of a freshly-assigned custom bit. Rename the sample custom
taints to 'graphql'/'graphql-json' (deliberately not builtin) so the
test keeps exercising custom-taint registration/caching.
Co-Authored-By: Claude Opus 4.8
Collaborator
Author
|
bugbot review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c1c4b86. Configure here.
danog
added a commit
to danog/psalm
that referenced
this pull request
Sep 22, 2026
Add nosql taint type and mark MongoDB sinks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new
nosqltaint type (part of theinputtaint class) and marks the appropriate MongoDB driver parameters as sinks, so user-controlled data flowing into a MongoDB query/command/filter is reported.This is the
master(bitmask taint design) counterpart of #11943 (which targets6.x).Changes
TaintKind::INPUT_NOSQL, added toALL_INPUTandTAINT_NAMES(USER_SECRET/SYSTEM_SECRETbits shifted up to keepALL_INPUTcontiguous;BUILTIN_TAINT_COUNTbumped to 20).TaintedNosqlissue (shortcode 369), wired intoTaintFlowGraphandconfig.xsd.stringcan never be a NoSQL query, sogetTaintsToRemove()stripsnosqlfrom string-typed values — casting user input tostringacts as a natural escape (newTaintKind::ARRAY_ONLY, mirroring the existingNUMERIC_ONLY/BOOL_ONLYdesign forsleep).stubs/extensions/mongodb.phpstub:MongoDB\Driver\Query::__construct$filterMongoDB\Driver\Command::__construct$documentMongoDB\Driver\BulkWrite::insert/update/deletefilter and document paramsMongoDB\Driver\Managerso the documented example is runnable.TaintedNosql.mdwith concrete injection examples and safe alternatives (cast to string,@psalm-taint-escape nosql), plus positive/negative test coverage inTaintTest.Test plan
vendor/bin/phpunit tests/TaintTest.phpvendor/bin/phpunit tests/DocumentationTest.php🤖 Generated with Claude Code