Summary
Add a first-class material type for Oversecured scan reports so mobile (Android/iOS) results can be attested and policy-evaluated like any other scanner output.
Today the only way to bring an Oversecured report into an attestation is the generic EVIDENCE kind with a hand-written chainloop.material.evidence.id wrapper. That works, but it pushes the wrapping onto every caller, skips validation at craft time, and gives the UI nothing to key off.
About the tool
Oversecured is a commercial SAST + DAST scanner built for mobile binaries only (~175 Android / ~85 iOS vulnerability classes). It has a REST API and a CLI, and exports a scan report in json, csv, md and pdf — there is no SARIF output, so it can't be routed through the existing SARIF kind.
Obtaining the report:
oversecured report <scanId> --app <appId> --format json
# or
GET /workspaces/{workspaceId}/apps/{appId}/scans/{scanId}/export?format=jsonReport shape
The per-finding fields worth relying on:
| Field | Notes |
|---|
category.severity | high | medium | low — severity lives on the category, not the instance |
category.id | Stable category UUID — the natural rule id |
category.descriptionTitle / descriptionText | Title and description of the vulnerability class |
category.descriptionRemediation | Remediation guidance |
category.platform | android | ios |
hasSast / hasDast | How the finding was reached; DAST means reproduced on the running app |
sources[] / sink | Taint flow, {code, file?, line}. Empty/null for config-only findings |
code[] | Decompiled snippets, lines[].is_matched marks the offending lines |
folderId | Triage bucket; the system false_positives folder is one of them |
llmDescription | AI write-up: impact, howToFix[], CVSS-style vector, tags |
hash | Documented as a stable identity across scans (detail endpoint) |
Proposed work in this repo
app/controlplane/api/workflowcontract/v1/crafting_schema.proto — add OVERSECURED_JSON = 43 (next free value)app/controlplane/api/workflowcontract/v1/crafting_schema_validations.gopkg/attestation/crafter/materials/oversecured.go + test, following the shape of gitleaks.go: read the file, confirm it parses as an Oversecured report, then uploadAndCraft- register the crafter in
pkg/attestation/crafter/materials/materials.go - regenerate the jsonschema / TS artifacts and add the row to the material types docs table
Format detection
Validate the export envelope, and when findings are present require the first one to carry a category with a severity in {high, medium, low} and a non-empty descriptionTitle. An empty report must be accepted — a clean scan is the common CI case and rejecting it would break passing pipelines.
One thing to confirm against a real export before implementing: the published docs describe the GET …/vulnerabilities list item and the single-finding detail response, but not the exact top-level envelope that export?format=json returns. The detection heuristic should be pinned to whatever that envelope actually is.
Making it work with SAST evaluation
The material type on its own doesn't make the report evaluable — the sast policy needs a new execution path (- kind: OVERSECURED_JSON) whose rego maps Oversecured findings onto the structured finding shape that family already consumes (message, rule_id, severity, severity_score, location, recommendation). Suggested mapping:
severity_score: high → 7.5, medium → 5.5, low → 2.0, lining up with the existing severity_score_maprule_id: category.idmessage: category.descriptionTitlelocation: sink.file:sink.line, falling back to the first code[].file containing an is_matched linerecommendation: category.descriptionRemediation- skip findings sitting in the system
false_positives folder, so the tool's own triage is honoured - consider an input to count only DAST-confirmed findings (
hasDast), which Oversecured's own --fail-on can't express since it is severity-only and includes findings triaged as false positives
Worth noting for whoever writes that rego: Oversecured findings carry neither CWE nor CVE identifiers, so the cwe-top25 and owasp-top10-* families will never match them. sast is the right home, and the only one.
The material type also needs syncing into the platform-side enum and the evidence UI mapping, tracked separately.
🤖 Posted by Maximus bot (Claude Code) on behalf of @migmartri
Summary
Add a first-class material type for Oversecured scan reports so mobile (Android/iOS) results can be attested and policy-evaluated like any other scanner output.
Today the only way to bring an Oversecured report into an attestation is the generic
EVIDENCEkind with a hand-writtenchainloop.material.evidence.idwrapper. That works, but it pushes the wrapping onto every caller, skips validation at craft time, and gives the UI nothing to key off.About the tool
Oversecured is a commercial SAST + DAST scanner built for mobile binaries only (~175 Android / ~85 iOS vulnerability classes). It has a REST API and a CLI, and exports a scan report in
json,csv,mdandpdf— there is no SARIF output, so it can't be routed through the existingSARIFkind.Obtaining the report:
Report shape
The per-finding fields worth relying on:
category.severityhigh|medium|low— severity lives on the category, not the instancecategory.idcategory.descriptionTitle/descriptionTextcategory.descriptionRemediationcategory.platformandroid|ioshasSast/hasDastsources[]/sink{code, file?, line}. Empty/null for config-only findingscode[]lines[].is_matchedmarks the offending linesfolderIdfalse_positivesfolder is one of themllmDescriptionhowToFix[], CVSS-style vector, tagshashProposed work in this repo
app/controlplane/api/workflowcontract/v1/crafting_schema.proto— addOVERSECURED_JSON = 43(next free value)app/controlplane/api/workflowcontract/v1/crafting_schema_validations.gopkg/attestation/crafter/materials/oversecured.go+ test, following the shape ofgitleaks.go: read the file, confirm it parses as an Oversecured report, thenuploadAndCraftpkg/attestation/crafter/materials/materials.goFormat detection
Validate the export envelope, and when findings are present require the first one to carry a
categorywith aseverityin{high, medium, low}and a non-emptydescriptionTitle. An empty report must be accepted — a clean scan is the common CI case and rejecting it would break passing pipelines.One thing to confirm against a real export before implementing: the published docs describe the
GET …/vulnerabilitieslist item and the single-finding detail response, but not the exact top-level envelope thatexport?format=jsonreturns. The detection heuristic should be pinned to whatever that envelope actually is.Making it work with SAST evaluation
The material type on its own doesn't make the report evaluable — the
sastpolicy needs a new execution path (- kind: OVERSECURED_JSON) whose rego maps Oversecured findings onto the structured finding shape that family already consumes (message,rule_id,severity,severity_score,location,recommendation). Suggested mapping:severity_score:high→ 7.5,medium→ 5.5,low→ 2.0, lining up with the existingseverity_score_maprule_id:category.idmessage:category.descriptionTitlelocation:sink.file:sink.line, falling back to the firstcode[].filecontaining anis_matchedlinerecommendation:category.descriptionRemediationfalse_positivesfolder, so the tool's own triage is honouredhasDast), which Oversecured's own--fail-oncan't express since it is severity-only and includes findings triaged as false positivesWorth noting for whoever writes that rego: Oversecured findings carry neither CWE nor CVE identifiers, so the
cwe-top25andowasp-top10-*families will never match them.sastis the right home, and the only one.The material type also needs syncing into the platform-side enum and the evidence UI mapping, tracked separately.
🤖 Posted by Maximus bot (Claude Code) on behalf of @migmartri