feat(detection): close the Python insecure-deserialisation gaps (#87) - #103
Merged
Conversation
Closes #87. Gaps identified by @AdvaitVarhade in #91, credited in CONTRIBUTORS. Extends the EXISTING unsafe-deserialisation block rather than adding a second one. That distinction is the whole reason #91 could not be merged as written: findings dedup on (file, line, category), so a parallel rule using a different category name for the same class defeats the dedup and doubles every pickle/yaml finding in every scanned repo. One rule_id per class, one category. Now flagged: * marshal.loads / marshal.load — executes arbitrary code while decoding * shelve.open — pickle-backed, same exposure * yaml.unsafe_load * yaml.load(x, Loader=yaml.Loader) — the best catch of the three. The old check was `not any(kw.arg == "Loader")`, i.e. ANY Loader counted as safe, so an explicitly unsafe loader passed silently. Also fixes a pre-existing FALSE POSITIVE it exposed: the old check only inspected keywords, so `yaml.load(x, yaml.SafeLoader)` — a positional safe loader — was flagged. The Loader is now read from the keyword or the second positional arg and matched on its last path segment, so `yaml.SafeLoader`, a bare imported `SafeLoader`, and `CSafeLoader` are all recognised. Verified: every case reports exactly ONCE (the 8-line fixture that went 2 findings -> 4 under #91 stays at 2), all five safe forms stay silent, and 283 tests pass with ruff clean.
Signetry Reviewer — 🟡 Needs human reviewA human should decide — the required check is pending. Deterministic gates (the authority)
FindingsNo issues found by the deterministic scanners. MergeA human should review and merge.
|
This was referenced Aug 18, 2026
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.
Closes #87. The gaps were identified by @AdvaitVarhade in #91 — credited in
CONTRIBUTORS.mdand the changelog.Extends the existing block, rather than adding a second one
That distinction is the entire reason #91 couldn't merge as written. Findings dedup on
(file, line, category), so a parallel rule using a different category name for the same class defeats the dedup and doubles every finding. Onerule_idper class, one category.Measured on the same 8-line fixture from that review:
mainbeforeNow flagged
marshal.loads/loadshelve.openyaml.unsafe_loadyaml.load(x, Loader=yaml.Loader)That last one is the best catch of the set. The old condition was:
i.e. any
Loader=counted as safe — so an explicitly unsafe loader passed silently. The Loader is now resolved and matched, not merely counted.Also fixes a pre-existing false positive it exposed
Because the old check only inspected keywords, a positional safe loader was flagged:
The Loader now comes from the keyword or the second positional argument, matched on its last path segment — so
yaml.SafeLoader, a bare importedSafeLoader, andCSafeLoaderare all recognised.All five safe forms verified silent:
Loader=yaml.SafeLoader·Loader=SafeLoader· positionalyaml.SafeLoader·Loader=yaml.CSafeLoader·yaml.safe_load.Verification
283 tests pass,
ruffclean. Three new tests: the four newly-caught cases, the five safe forms, and ascan_repositorytest asserting exactly two findings on the duplicate fixture with a single category — which is the regression that would catch a future parallel-rule mistake.On #91
I'll close it pointing here. @AdvaitVarhade found three real gaps that
maingenuinely missed — that's the hard part — and the review offered to land the patch with credit if they preferred not to rewrite. Credit is inCONTRIBUTORS.mdand the changelog.