Back to skill

Security audit

Axe DevTools

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-built for axe accessibility testing, but it runs an unpinned Docker image and passes an Axe API key and page data into that container.

Install only if you are comfortable running Deque's Docker image locally and sending tested page URLs, HTML snippets, and remediation text to the Axe MCP service. Prefer a digest-pinned image, restrict Docker access, avoid scanning sensitive internal pages without approval, and rotate the Axe API key if command logging or Docker inspection may expose it.

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)

T08 · Insecure Dependencies

Warning
Location
scripts/axe-mcp.js:13
Finding

Mutable Docker Image Is Executed Without Digest Pinning

Content
View full analysis

Vulnerability Details

File Location: scripts/axe-mcp.js:13, 31-38; SKILL.md:12-16
Vulnerability Type: Supply-chain risk caused by an unpinned executable dependency
Risk Level: Medium

Vulnerable Code

scripts/axe-mcp.js:13:

js
const DOCKER_IMAGE = "dequesystems/axe-mcp-server:latest";

scripts/axe-mcp.js:31-38:

js
const dockerArgs = [
  "run", "-i", "--rm",
  "-e", `AXE_API_KEY=${AXE_API_KEY}`,
];
if (process.env.AXE_SERVER_URL) {
  dockerArgs.push("-e", `AXE_SERVER_URL=${process.env.AXE_SERVER_URL}`);
}
dockerArgs.push(DOCKER_IMAGE);

SKILL.md:12-16:

markdown
## Prerequisites

- Docker running locally
- `AXE_API_KEY` environment variable set
- Docker image pulled: `dequesystems/axe-mcp-server:latest`

Technical Analysis

The wrapper executes dequesystems/axe-mcp-server:latest, which is a mutable image reference. The image content associated with the latest tag can be replaced after the Skill has been audited. Consequently, the code that ultimately runs is not cryptographically bound to a reviewed artifact.

Although the image is obtained from the documented vendor namespace, relying on a mutable tag leaves execution dependent on the ongoing security of the upstream publisher account, registry, and release process. A compromised publisher account, registry compromise, or unsafe future image release could silently change the effective executable payload.

Attack Path

  1. An attacker compromises the upstream image publication process or gains the ability to replace the image associated with the latest tag.
  2. The attacker publishes a modified image under dequesystems/axe-mcp-server:latest.
  3. A user pulls the updated image or runs the wrapper on a system configured to obtain the current tag.
  4. The wrapper starts the attacker-controlled image through Docker.
  5. The malicious container receives AXE_API_KEY, the optional `AXE_S ...[truncated 942 chars]
Remediation
View remediation

Remediation Suggestions

  1. Pin the Docker image to a reviewed immutable digest:

    js
    const DOCKER_IMAGE =
      "dequesystems/axe-mcp-server@sha256:<reviewed-image-digest>";
    
  2. Verify the digest against an authenticated vendor release channel before adoption.

  3. Establish a controlled update process in which new image digests are scanned, tested, reviewed, and explicitly committed.

  4. Use signature verification, such as Sigstore/Cosign, if supported by the image publisher.

  5. Add automated policy checks that reject mutable tags such as latest in executable container references.

  6. Apply additional container restrictions where compatible, including a read-only filesystem, dropped Linux capabilities, no-new-privileges, resource limits, and constrained network access.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/axe-mcp.js:31
Finding

Axe API Key Is Embedded Directly in Docker Command Arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/axe-mcp.js:5-9, 31-35
Vulnerability Type: Sensitive credential exposure through process arguments and container configuration
Risk Level: Medium

Vulnerable Code

scripts/axe-mcp.js:5-9:

js
const AXE_API_KEY = process.env.AXE_API_KEY;
if (!AXE_API_KEY) {
  console.error("Error: Set AXE_API_KEY environment variable");
  process.exit(1);
}

scripts/axe-mcp.js:31-35:

js
const dockerArgs = [
  "run", "-i", "--rm",
  "-e", `AXE_API_KEY=${AXE_API_KEY}`,
];
if (process.env.AXE_SERVER_URL) {

Technical Analysis

The secret value is concatenated into the argument array passed to the Docker CLI as AXE_API_KEY=<secret>. This can expose the credential through operating-system process inspection while the Docker command is running. It also places the secret in the created container's environment, where it may be visible through Docker inspection to users or services with Docker daemon access.

Passing secrets in command arguments is unsafe because command-line values can be collected by process-monitoring utilities, diagnostic agents, audit systems, crash reports, or sufficiently privileged local users. The --rm option removes the container after execution but does not prevent observation while it is running.

Attack Path

  1. A user invokes node scripts/axe-mcp.js analyze ... or another supported command.
  2. The wrapper starts Docker with -e AXE_API_KEY=<credential> in its argument vector.
  3. A local process or user with sufficient process visibility records the Docker command before it exits, or a principal with Docker access inspects the running container's environment.
  4. The observer extracts the Axe API key.
  5. The recovered key is reused against the corresponding Axe service.

Exploitation requires local process visibility, Docker daemon access, or access to monitoring data that records command arg ...[truncated 707 chars]

Remediation
View remediation

Remediation Suggestions

  1. Do not include the credential value directly in Docker's command-line arguments.

  2. Where Docker behavior and the execution environment permit it, pass only the environment variable name:

    js
    const dockerArgs = [
      "run", "-i", "--rm",
      "-e", "AXE_API_KEY",
    ];
    

    Ensure the Docker client process inherits AXE_API_KEY without adding its value to the argument vector.

  3. Prefer a dedicated secret mechanism if the container supports file-based credentials, such as Docker secrets or a strictly permissioned temporary secret file mounted read-only.

  4. If a temporary secret file is necessary, create it with owner-only permissions, avoid predictable paths, and guarantee deletion on success, failure, interruption, and timeout.

  5. Restrict access to the Docker daemon because Docker-authorized principals can inspect container configuration and commonly possess extensive host capabilities.

  6. Rotate the current API key if process monitoring, command logging, or Docker inspection may already have captured it.

  7. Configure monitoring and audit systems to redact credential-bearing environment and command data.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (10)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 18)May include surrounding context.

md
The wrapper script at `scripts/axe-mcp.js` (Node.js — no extra dependencies) provides two tools:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 25)May include surrounding context.

md
The wrapper script at `scripts/axe-mcp.js` (Node.js — no extra dependencies) provides two tools:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 35)May include surrounding context.

md
The wrapper script at `scripts/axe-mcp.js` (Node.js — no extra dependencies) provides two tools:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 45)May include surrounding context.

md
The wrapper script at `scripts/axe-mcp.js` (Node.js — no extra dependencies) provides two tools:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 52)May include surrounding context.

md
The wrapper script at `scripts/axe-mcp.js` (Node.js — no extra dependencies) provides two tools:

MCP Config Access

High
Category
Agent Snooping
Confidence
80% confidence
Finding

Skill accesses MCP server configuration files (mcp.json). MCP configs contain server URLs, authentication tokens, and tool definitions — reading them allows the skill to discover and potentially abuse other tool integrations.

Content

Scanner excerpt · SKILL.md (reported line 42)May include surrounding context.

tools-list

List available MCP tools.

bash
node scripts/axe-mcp.js tools-list

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill instructs use of a Node wrapper that accesses environment variables (AXE_API_KEY) and performs networked operations against a remote service, but the manifest declares no explicit tool scope or permission boundaries. This creates a least-privilege gap: an agent or reviewer cannot tell from the skill metadata what sensitive capabilities are required, increasing the chance of unintended secret exposure or unauthorized network use.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The wrapper launches a Docker container on the host, which is a significant execution capability not disclosed by the skill description. In environments where agent skills are expected to be low-privilege helpers, invoking Docker can expand the trust boundary, pull and run mutable images, and grant indirect host-level effects through the container runtime.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The manifest describes an accessibility testing/remediation skill for UI code, but this wrapper explicitly depends on a secret credential in the runtime environment and passes it into the container. While external service access may be implementation-related, handling environment-based credentials is a distinct capability not disclosed in the skill description and is not obviously inherent from the manifest alone.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The analyze and remediate commands forward user-supplied URLs, HTML fragments, and remediation text into an external Dockerized service without any notice, confirmation, or data-sensitivity checks. That can leak proprietary page content, internal URLs, or sensitive markup to a third-party processing service, which is especially relevant because this skill is likely to be used on unreleased or internal UI code.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/axe-mcp.js:44