Skip to content

feat(checks): flag insecure deserialization introduced in a PR diff - #21

Merged
bkd-dotcom merged 1 commit into
mainfrom
feat/deserialization-check
Aug 18, 2026
Merged

feat(checks): flag insecure deserialization introduced in a PR diff#21
bkd-dotcom merged 1 commit into
mainfrom
feat/deserialization-check

Conversation

@bkd-dotcom

Copy link
Copy Markdown
Member

Closes #2.

scan_deserialization flags a deserialization sink that an added line introduces:

language sinks
Python pickle.load(s), marshal.load(s), shelve.open, yaml.load without a safe Loader, yaml.unsafe_load
Java new ObjectInputStream(...), .readObject()
PHP unserialize(
Ruby Marshal.load, YAML.load
.NET BinaryFormatter, NetDataContractSerializer, LosFormatter, ObjectStateFormatter

Advisory, never blocking

As the issue specifies. Deserialization is the shape of an RCE surface, but whether the input is attacker-controlled cannot be read off a diff hunk — a fixture loading its own cache artifact is routine. So this adds context for the reviewer and never decides mergeability, matching how arch.dynamic_exec treats eval/exec.

Precision

  • Added lines only — a removed sink is a fix, not a finding. Tested with a removal-only diff.
  • Whole-line comments skipped (#, //, *, /*). This is deliberate: it's precisely the mistake ci.pull_request_target made, where documenting a risk tripped the rule meant to catch it (fix(checks): CI rules fired on YAML comments; tighten pull_request_target to the real trigger #18).
  • Safe forms not flagged: yaml.load(..., Loader=SafeLoader), Loader=CSafeLoader, Loader=BaseLoader, yaml.safe_load, json.loads. yaml.unsafe_load always is.
  • One finding per added line — first matching sink wins, so a line isn't double-reported.
  • Test paths report MEDIUM, not HIGH (tests/, fixtures/, testdata/, examples/, benchmarks/) — still surfaced, weighted for what it is.

Verification

37 tests pass, ruff clean. 6 new tests: all ten sinks across six languages, advisory/non-blocking behaviour, the four safe forms, comments in both Python and Java styles, added-lines-only, and the test-path severity split.

This was the last open code issue in this repo.

Closes #2.

scan_deserialization flags a deserialization sink an added line
introduces, across Python (pickle, marshal, shelve, yaml.load without a
safe Loader, yaml.unsafe_load), Java (ObjectInputStream / readObject),
PHP (unserialize), Ruby (Marshal.load / YAML.load) and .NET
(BinaryFormatter, NetDataContractSerializer, LosFormatter,
ObjectStateFormatter).

Advisory, never blocking, as the issue asks. Deserialization is an RCE
surface, but whether the input is attacker-controlled cannot be decided
from a diff hunk — a fixture loading its own artifact is routine. So this
adds reviewer context and never decides mergeability, matching how
arch.dynamic_exec treats eval/exec.

Precision details:
  * added lines only, so a REMOVED sink (a fix) is not a finding
  * whole-line comments are skipped in all four comment styles — the
    mistake ci.pull_request_target made, where documenting a risk tripped
    the rule meant to catch it
  * yaml.load(..., Loader=SafeLoader/CSafeLoader/BaseLoader),
    yaml.safe_load and json.loads are not flagged; yaml.unsafe_load
    always is
  * one finding per added line (first matching sink wins)
  * sinks under tests/fixtures/testdata/examples/benchmarks report MEDIUM
    instead of HIGH

6 tests: all ten sinks across six languages, advisory/non-blocking, the
four safe forms, comments in Python and Java, added-lines-only via a
removal-only diff, and the test-path severity split.
@bkd-dotcom
bkd-dotcom merged commit f411182 into main Aug 18, 2026
4 checks passed
@bkd-dotcom
bkd-dotcom deleted the feat/deserialization-check branch August 18, 2026 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Check: flag insecure deserialization introduced in a PR diff

1 participant