Skip to content

feat(java): detect cloud agent provisioning in pipeline Steps without an ACL permission check (CWE-862) - #158

Open
ai-anant wants to merge 9 commits into
CodeVigilant:mainfrom
ai-anant:rule/java-jenkins-cloud-provision-step-without-permission
Open

feat(java): detect cloud agent provisioning in pipeline Steps without an ACL permission check (CWE-862)#158
ai-anant wants to merge 9 commits into
CodeVigilant:mainfrom
ai-anant:rule/java-jenkins-cloud-provision-step-without-permission

Conversation

@ai-anant

Copy link
Copy Markdown

Detect a Jenkins pipeline Step / StepExecution (or helper) that registers, provisions or launches a cloud agent/task template (e.g. addDynamicTemplate, registerTemplate, cloud.provision(...), launchAgent) without an explicit ACL authorization check (checkPermission / hasPermission / Jenkins.get().checkPermission(...)) in the same method.

Without this, any user able to run such a pipeline can provision additional agents/containers on the configured cloud and inherit the cloud's IAM identity, privileged container settings, and mounted credentials (CWE-862 Missing Authorization).

Pattern shape (generic):

  • sink: $REC.$PROVISION(...) where $PROVISION is a cloud agent/task provisioning operation
  • pattern-not-inside excludes methods that already guard with a permission check

Validated with semgrep 1.174: positive repro fires, permission-guarded negative does not.

Automated CVE monitoring that:
- Checks WordPress.org API + NVD for new plugin/theme vulnerabilities
- Downloads affected plugin source code
- Runs semgrep rules to detect coverage
- Creates PRs with new rules for missed detections
- Comments on tracking issue (#1) with detection matrix

Runs every 4 hours via Hermes cron job.
- Fix gh API JSON body handling (use temp file + --input flag)
- Fix XSS rule pattern (use pattern-regex instead of invalid echo ...)
- Fix SSRF rule pattern (target user input in file_get_contents)
- Fix generic template pattern (use proper semgrep pattern-either)
- Add better plugin name extraction from NVD descriptions
- Fix WordPress.org API URL (use recent updates endpoint)
- Add download error handling and timeout per plugin
- Quote YAML message fields to avoid colon parsing issues
- Limit to 10 CVEs per run to avoid timeout
Key insight: WordPress.org only serves patched plugin versions, so
scanning downloaded code always shows 'not caught'. Instead:

- Analyze CVE descriptions to extract vulnerability patterns
- Check existing semgrep rules against those patterns
- Only flag as 'missed' when no rules cover the pattern type
- Removed broken WordPress.org recent-updates source (not actual CVEs)
- Removed plugin download/scan logic (can't get vulnerable versions)
- All 8 current NVD CVEs correctly identified as caught by existing rules

This is the correct approach for a detection-gap analysis.
…h-bypass

The classifier dropped 12 of 20 CVEs in the 7-day NVD window as 'unknown'
type because keyword lists were too narrow (e.g. stored XSS described as
'does not sanitise or escape ... store JavaScript' without the literal
'xss' phrase). Added:
- XSS phrasing keywords (sanitise/escape/javascript/unfiltered_html)
- CSRF nonce keywords ('nonce check', 'capability or nonce')
- New types: idor, information_disclosure, auth_bypass with pattern
  extraction and rule-coverage mappings
- Multi-word plugin slug extraction ('Ultimate Member' -> ultimate-member)
- Drop leading 'the-' article from captured names

Verified against 20-CVE NVD window: all 12 previously-dropped CVEs now
classify correctly (9 caught, 3 CSRF misses reported on issue #1).
fetch_nvd_wordpress_cves() used resultsPerPage=20 with no startIndex loop,
so the monitor only ever saw the first ~18-20 CVEs of a ~200+ CVE window.
Every 'No new CVEs' verdict was filter-blind: ~139 filter-passing CVEs per
cycle aged out of the window silently, never analyzed, never recorded.

Now loops startIndex until totalResults (resultsPerPage=2000), matching the
independently-verified verify-nvd-window probe. First fixed run (2026-08-09
18:36 UTC): 157 window CVEs fetched (was 18), 139 backlog CVEs analyzed —
120 caught by existing rules, 19 missed (all CSRF, zero nonce-verification
rules), detection matrix posted to issue #1.
The coverage classifier's csrf category only searched rule IDs for
'nonce-verification'/'restricted-hooks', but the actual CSRF rules are
id'd codevigilant.php.coding-standards.csrf.nonce.* — so every CSRF CVE
was falsely reported as MISSED despite 3 matching rules. Add 'csrf' to
the rule_patterns list; verified no regression in rce/idor/priv-esc
categories.
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.

1 participant