Back to skill

Security audit

WCAG 2.1 AA Web UI Audit

Security checks for vulnerabilities and agentic risk

Overview

This accessibility-audit skill is coherent and user-directed, with manageable caution around scanning only trusted URLs and installing dependencies carefully.

Install only if you are comfortable with a skill that can run a local browser against URLs you provide and write local audit reports. Use trusted target URLs, avoid attacker-supplied URL lists, avoid running it from privileged internal networks unless intended, and pin/review npm dependencies before following the optional install guidance.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run_axe_playwright.js:66
Finding
Unrestricted URL Navigation Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run_axe_playwright.js:66-83`, with the resulting navigation at `scripts/run_axe_playwright.js:288` **Vulnerability Type**: Server-Side Request Forgery through unrestricted browser navigation **Risk Level**: Medium ### Vulnerable Code ```js function normalizeUrl(raw) { if (!raw) { return null; } const value = String(raw).trim(); if (!value) { return null; } try { const url = new URL(value); if (url.protocol !== "http:" && url.protocol !== "https:") { return null; } return url.toString(); } catch (_error) { return null; } } ``` The accepted URL is subsequently opened by headless Chromium: ```js await page.goto(url, { waitUntil: "domcontentloaded", timeout: timeoutMs }); ``` ### Technical Analysis The URL validation only restricts the protocol to HTTP or HTTPS. It does not reject: - IPv4 or IPv6 loopback addresses - RFC 1918 private-network addresses - Link-local addresses - Cloud instance metadata endpoints - Internal DNS hostnames - Public URLs that redirect to private or link-local destinations - URLs containing embedded credentials or sensitive query parameters Because `page.goto()` performs the request from the environment running the audit, an attacker who controls an audit URL or URL-list entry can cause that environment to access services that may not be reachable from the attacker's own network. Axe subsequently examines the loaded page. Selected DOM evidence, including violation-related HTML, selectors, page URLs, and errors, can be written to `outputs/axe-results.json` and `outputs/axe-summary.md`. The reviewed code does not transmit these files to an external party, so extraction would require access to generated outputs or another disclosure mechanism. ### Attack Path 1. An attacker supplies or influences a URL passed through `--url` or `--urls-file`. 2. The attacker uses a destination such as a loopback service, private-network ...[truncated 1562 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Resolve destination hostnames before navigation and reject all resolved addresses in prohibited ranges, including: - IPv4 and IPv6 loopback - RFC 1918 private networks - IPv4 and IPv6 link-local ranges - Unique-local IPv6 ranges - Multicast, reserved, and unspecified addresses - Known cloud metadata addresses 2. Revalidate every redirect destination. Initial URL validation alone is insufficient because a public endpoint can redirect to an internal address. 3. Use a default-deny hostname allowlist where possible. If internal accessibility auditing is required, enable it only through an explicit option and document the associated trust requirements. 4. Run Chromium in a network-isolated environment with egress rules that prevent access to internal control planes and metadata services. 5. Reject URLs containing username/password components and redact sensitive query strings before logging or persisting them. 6. Limit response size, redirect count, and total navigation time to reduce denial-of-service exposure. 7. Add automated tests covering loopback, private IPv4, private IPv6, link-local, alternative IP representations, internal DNS resolution, DNS rebinding, and redirects to prohibited destinations. ]]>

T08 · Insecure Dependencies

Note
Location
scripts/run_axe_playwright.js:363
Finding
Unpinned Dependency Installation Guidance Creates Supply-Chain Risk<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run_axe_playwright.js:363` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Low ### Vulnerable Code ```js console.log("[wcag-21-aa-web-ui-audit] Install with: npm install -D playwright @axe-core/playwright"); ``` ### Technical Analysis When optional dependencies are unavailable, the script recommends installing `playwright` and `@axe-core/playwright` without explicit versions. The audited project does not include a `package.json` or committed lockfile that defines reviewed versions and integrity data. As a result, the command resolves whatever package versions and transitive dependencies are current in the configured npm registry at installation time. This makes installation non-reproducible and expands exposure to: - A future compromised package release - A compromised transitive dependency - Registry or configuration manipulation - Unexpected breaking or security-relevant behavior in later releases - Package lifecycle scripts executed during installation The package names are consistent with the script's declared accessibility-testing purpose. No typo-squatted package, malicious registry, or known malicious version was identified in the reviewed files. The issue is the mutable, unreviewed resolution process rather than evidence that the named packages are malicious. ### Attack Path 1. The user runs the automation script without the optional modules installed. 2. The script prints the unpinned `npm install` command. 3. The user follows that guidance. 4. npm resolves the latest available versions from the user's configured registry, along with mutable transitive dependencies. 5. If a resolved package, transitive dependency, registry, or account has been compromised, attacker-controlled installation code may execute with the user's npm process privileges. 6. The compromised package may then affect subsequent execution of the audit script. ### Impact Assess ...[truncated 663 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a minimal `package.json` declaring exact, reviewed dependency versions rather than floating ranges. 2. Generate and commit `package-lock.json` so package versions and integrity hashes are reproducible. 3. Replace the installation recommendation with `npm ci` after directing users to the committed manifest and lockfile. 4. Review dependency updates through a controlled process that includes changelog review, vulnerability scanning, and lockfile-diff inspection. 5. Configure CI to fail when the lockfile and manifest are inconsistent. 6. Use an approved registry and protect npm configuration from unauthorized registry overrides. 7. Where operationally suitable, disable lifecycle scripts during installation with `npm ci --ignore-scripts`, then explicitly perform any required trusted Playwright browser installation step. 8. Run dependency installation and browser automation in a least-privileged container or sandbox without production credentials. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
The code clearly relates to web accessibility auditing, so the domain is aligned with the description. It accepts URLs, launches Chromium via Playwright, runs @axe-core/playwright, deduplicates violations, and writes results to outputs/axe-results.json and outputs/axe-summary.md. However, the declared purpose overstates what the implementation does. This script is an automated baseline scanner only, which the code itself explicitly notes in the Markdown output. It does not create a remediation backlog, does not perform manual or comprehensive WCAG 2.1 Level AA evaluation, and does not implement the broader review/conformance activities implied by the description. Therefore this is a description-behavior mismatch due to materially narrower actual functionality, not because of any unrelated or malicious extra capability.

Ae1

High
Category
analysis-evasion
Content
node scripts/run_axe_playwright.js --url https://example.com
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/run_axe_playwright.js --url https://example.com
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Anti-Refusal Statement

High
Category
Anti-Refusal
Content
Common impacted components: Menu items, form fields, auto-open popups.

### SC 3.2.2 On Input (Level A)
UI meaning: Changing input value must not unexpectedly submit/navigate without warning.
Common impacted components: Filters, selects, toggles, settings controls.

### SC 3.2.3 Consistent Navigation (Level AA)
Confidence
80% confidence
Finding
Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
| ID | Flow/Page | Component | WCAG SC (ID • Name • Level) | Severity | Affected Users | Issue Summary | Repro Steps | Expected | Actual | Recommended Fix (Design + Dev) | Verification (Manual + Tool) | Status |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| F-001 | Product -> Cart Drawer | Drawer | 2.1.2 • No Keyboard Trap • A; 2.4.3 • Focus Order • A; 2.4.7 • Focus Visible • AA | Blocker | Keyboard-only, Screen reader, Motor | Focus enters drawer but tabs behind overlay and cannot reliably reach close button. | Open product page, add item, open cart drawer, tab forward repeatedly. | Focus stays in drawer and close control is reachable. | Focus escapes to background and return path is unclear. | Design: preserve visible close action placement and focus ring style. Dev: implement managed focus loop, initial focus on drawer title/close, return focus to trigger on close. | Manual keyboard traversal + axe + screen reader smoke check. | Open |
| F-002 | Checkout Payment Step | Form fields and error states | 3.3.1 • Error Identification • A; 3.3.3 • Error Suggestion • AA; 3.3.4 • Error Prevention (Legal, Financial, Data) • AA; 1.4.1 • Use of Color • A | High | Screen reader, Low vision, Cognitive/learning | Card errors are shown as red outlines only with generic message and no correction guidance; no review step before final charge. | Submit invalid card details, observe field errors and final submit behavior. | Errors include field-specific guidance and review/confirm safeguard before charge. | Error text is generic, color-only cue used, and no confirmation step for critical submit. | Design: explicit field-level error copy and review checkpoint pattern. Dev: bind errors via `aria-describedby`, set `aria-invalid`, add pre-submit review confirmation. | Manual form scenario tests + axe checks for ARIA associations. | Open |
| F-003 | Product Detail | Add-to-cart toast | 4.1.3 • Status Messages • AA | High | Screen reader, Cognitive/learn
...[truncated 26 chars]
Confidence
75% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Static analysis

No suspicious patterns detected.