Skip to content

[Feature] Expose the file surface a finding landed on (code / instructions / docs / tests / config) #326

Description

@Mark2Mac

Summary

Findings do not say what kind of file surface they landed on, and triage is much harder without it. This is a request to expose that information, not to filter on it — filtering is contentious for good reasons (see below), while the data itself is useful either way.

The measurement

Scanning 65 real skill/plugin units — 4415 findings, every one triaged by hand — and classifying each finding by the surface its line belongs to:

rule findings code instructions tests docs comments config
RP1 894 262 94 64 381 72 21
PE3 814 296 22 211 115 156 14
AST4 417 238 0 178 0 1 0
E1 390 69 7 262 36 7 9
RA2 235 88 24 24 44 48 7
AS3 207 7 44 33 48 6 69
MP2 194 48 20 24 87 15 0
EA3 175 103 1 8 62 1 0

Totals across all 53 rules: code 1442 · tests 981 · docs 980 · comments 412 · instructions (SKILL.md) 325 · config 275.

instructions is kept separate from docs on purpose: SKILL.md is not prose about a command, it is what the agent executes — which is exactly why _is_documentation_context already excludes it. Counting it as documentation overstates the "non-executable" share, and I made that mistake before correcting it.

Why exposing, and not filtering

Two of these columns look like obvious suppression candidates. They are not:

  • tests (981 findings). A fixture containing an attack string is expected — but a directory named tests/ is also exactly where a payload would hide. Exempting it trades a real detection for a cosmetic gain.
  • config — and the reason the aggregate is misleading. SC1 has 100% of its findings outside executable code, entirely in config files. For a dependency-pinning rule that is the correct place. "Not code" does not mean "noise", and the ratio only means something per rule.

Both arguments point the same way: the classification is genuinely useful for whoever reads the report, and genuinely dangerous as an automatic filter. So ship the data and let the consumer decide.

What this would look like

A normalised field on each finding — surface: code | instructions | docs | tests | config — derived from the path (and, for the comment case, from the matched line). The runner already computes file_type and _infer_file_type, so most of the input exists.

Concretely it would let a consumer:

  • sort a 400-finding report by surface and read the 238 code ones first;
  • write a suppression policy locally, taking on the risk explicitly, instead of the scanner taking it on their behalf;
  • diff two scans by surface, which is how one notices that a rule started matching documentation after a version bump — how the PE3 change in 2.4/2.5 became visible here at all.

I have not opened a PR because this touches the report schema, which is a public contract and yours to design. If the shape is welcome I am happy to implement it; if the answer is "the consumer can derive this from location.file", that is a fair answer too — it is what I ended up doing, and the reason I can post the table above.

Context

From the same corpus that produced #302, #319, #321, #322 and #323. Zero true positives in 4415 findings, which is a statement about this corpus (first-party and well-known marketplaces), not about the scanner.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions