Back to skill

Security audit

aperture: the L402 aware reverse proxy

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its stated purpose, but it installs mutable unverified upstream code that will run with access to Lightning invoice credentials.

Review before installing. Prefer a pinned Aperture version, run it as an unprivileged user, keep the macaroon limited to invoice-only permissions, and use --insecure or --no-auth only for isolated local development.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T08 · Insecure Dependencies

Warning
Location
scripts/install.sh:35
Finding
Unpinned Go Dependency Allows Unreviewed Upstream Code Installation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install.sh`, lines 35–51 **Vulnerability Type**: Mutable and unverified third-party dependency **Risk Level**: Medium ### Vulnerable Code ```bash # Default to @latest when no version specified. VERSION="${VERSION:-@latest}" echo "=== Installing Aperture ===" echo "" # Verify Go is installed. if ! command -v go &>/dev/null; then echo "Error: Go is not installed." >&2 echo "Install Go from https://go.dev/dl/" >&2 exit 1 fi echo "Go version: $(go version | grep -oE 'go[0-9]+\.[0-9]+')" echo "" # Install aperture. echo "Installing aperture..." go install "github.com/lightninglabs/aperture/cmd/aperture${VERSION}" ``` ### Technical Analysis When no version is supplied, the installation script uses the mutable `@latest` selector. Consequently, the code installed by the Skill can change after the Skill itself has been reviewed. The script does not pin an audited Aperture release or independently verify the selected source revision or resulting binary. The repository path is consistent with the declared Aperture project, and no evidence indicates that it is currently malicious. Nevertheless, relying on a mutable upstream version creates a supply-chain trust boundary. Compromise of the upstream repository, release process, a dependency, or relevant module-distribution infrastructure could cause users to install an altered binary. The installed Aperture binary is later run with access to the configuration paths for an LND TLS certificate and invoice macaroon. These resources are necessary for the declared L402 functionality, but they increase the consequences of executing an unreviewed version. ### Attack Path 1. An attacker compromises the upstream Aperture repository, its release process, or one of the dependencies selected by the latest release. 2. The attacker publishes a newer version that contains malicious behavior. 3. A user runs `scripts/install.sh` without specifying `--version ...[truncated 1019 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace `@latest` with a specific, reviewed release: ```bash DEFAULT_VERSION="v0.4.2" VERSION="@${DEFAULT_VERSION}" ``` 2. Maintain an explicit allowlist of supported versions rather than accepting arbitrary module selectors. 3. Record and review the expected Go module checksums in a controlled `go.sum` by building from a pinned module checkout. 4. For higher-assurance deployment, publish a verified binary and validate it against a hardcoded SHA-256 digest before installation. 5. Treat version updates as security-relevant changes and require review before changing the pinned version. 6. Document that installation and execution should occur as an unprivileged, dedicated service account with access only to the invoice-specific macaroon required by Aperture. ]]>

T08 · Insecure Dependencies

Note
Location
templates/docker-compose-aperture.yml:41
Finding
BusyBox Container Uses a Mutable Latest Tag Without Digest Verification<![CDATA[ ## Vulnerability Details **File Location**: `templates/docker-compose-aperture.yml`, line 41 **Vulnerability Type**: Mutable container image dependency **Risk Level**: Low ### Vulnerable Code ```yaml backend: image: busybox:latest container_name: litd-backend restart: unless-stopped ``` ### Technical Analysis The Compose template obtains the backend container through the mutable `busybox:latest` tag. A tag is a registry reference rather than an immutable identity and may later resolve to different image content. The configuration does not pin the image to a digest. BusyBox is a well-known image and no evidence indicates that the current image is malicious. The weakness is that future deployments may execute image content that differs from the version originally reviewed. Compromise of the image publisher, registry account, registry infrastructure, or tag publication process could substitute malicious content. The backend container does not receive the LND credential volume. However, it shares `aperture-net` with Aperture and therefore has network access to that container. Its access is materially narrower than the Aperture container's access. ### Attack Path 1. An attacker compromises the BusyBox publication process, registry account, or mutable `latest` tag. 2. The `busybox:latest` reference is changed to point to an attacker-controlled image. 3. A user pulls or recreates the Compose stack. 4. Docker retrieves and starts the substituted image as the backend service. 5. The malicious container probes or attacks services reachable over `aperture-net`, supplies manipulated backend responses, or consumes host resources within the limits of the container runtime. 6. Further impact would require a vulnerable network service, exposed Docker capability, or container-runtime escape; none is established by the reviewed files. ### Impact Assessment Direct impact is primarily limited to the backend container and its attached Docker network ...[truncated 550 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin BusyBox to a reviewed version and immutable image digest: ```yaml image: busybox:1.36.1@sha256:<verified-digest> ``` 2. Verify the digest through the official image registry and update it only through a reviewed dependency-update process. 3. Apply container hardening controls where compatible: ```yaml read_only: true security_opt: - no-new-privileges:true cap_drop: - ALL ``` 4. Add memory, CPU, and process limits to reduce denial-of-service impact. 5. Keep the backend isolated from networks it does not require and avoid publishing its port directly to the host. 6. Consider using an internally built, minimal static backend image whose source and digest are controlled with the project. ]]>
Vulnerability Patterns
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill documents `--insecure` and `--no-auth` options without a strong, prominent warning that they disable TLS and payment/authentication protections. In the context of a reverse proxy intended to gate paid API access, normalizing these flags can lead users to expose services without transport security or access control, especially if bound beyond localhost or reused in non-development environments.

Session Persistence

Medium
Category
Rogue Agent
Content
### Invoice Macaroon Requirement

Aperture requires `invoice.macaroon` in the configured `macdir` to create
Lightning invoices for L402 challenges. This is **not** the same as
`admin.macaroon`. If the macaroon is missing, aperture will fail to start or
will return errors when clients request paid resources.
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
NETWORK="mainnet"
PORT="8081"
INSECURE=false
NO_AUTH=false
LND_HOST="localhost:10009"
LND_TLS="$HOME/.lnd/tls.cert"
LND_MACDIR=""
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Session Persistence

Medium
Category
Rogue Agent
Content
echo "Config:       $CONFIG_FILE"
echo ""

# Create aperture directory.
mkdir -p "$APERTURE_DIR"

# Build config.
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
if [ "$FOREGROUND" = true ]; then
    exec aperture --configfile="$CONFIG_FILE"
else
    nohup aperture --configfile="$CONFIG_FILE" \
        > "$LOG_FILE" 2>&1 &
    APERTURE_PID=$!
    echo "aperture started in background (PID: $APERTURE_PID)"
Confidence
65% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Missing User Warnings

Low
Confidence
84% confidence
Finding
This markdown file includes commands that create directories and files under /tmp and start a background HTTP server and Aperture instance. While the commands are instructional, this section does not explicitly warn users that it will write local files and launch network-accessible processes, which falls under missing user disclosure for markdown skills affecting system state.

Static analysis

No suspicious patterns detected.