If you discover a security vulnerability, please report it responsibly via the private GitHub Security Advisory channel:
- Do NOT open a public issue (public issues expose the vulnerability before it can be patched).
- Open a GitHub Security Advisory on the public repo. This is the only supported private disclosure channel — do not email or DM.
- Include: affected version (for example v2.0.0), reproduction steps, and impact assessment.
We aim to acknowledge reports within 48 hours and provide an estimated resolution timeline within 7 days.
Only the latest version receives security updates.
- No credentials or API keys are stored in this repository
- Install scripts write only to configured host roots, canonicalize destinations, reject link escapes and unowned file collisions, and record an ownership manifest. The Windows installer preflights its complete plan and rejects reparse-point, managed-environment, and late-file collisions before its first destination write.
- Python dependencies install in isolated virtual environments
- Shared SSRF validation (
scripts/url_utils.py) rejects non-public IPv4/IPv6, pins Requests to the validated numeric address while preserving Host/SNI/TLS verification, and re-enters the guard for every redirect. Playwright cannot pin Chromium's socket resolution, so browser dispatch is denied unless an external OS/container egress sandbox supplies a short-lived Ed25519-signed attestation bound to the current environment. Screenshot capture writes a digest-bound receipt naming the attestation, issuer, trust key, environment, and artifact. - Error messages are scrubbed via
sanitize_error()before reaching stdout, JSON output, or audit reports — stripskey=,token=,secret=,password=, and bareBearer <token>substrings - GitHub Actions are pinned to full commit SHAs; Dependabot auto-merge is restricted to patch updates only
pip-auditruns on every CI build and fails on any reported vulnerability (no severity threshold — strictest policy)
The following endpoints may be contacted at runtime. All user-supplied URLs pass through the SSRF blocklist before any fetch is attempted; trusted vendor endpoints are hardcoded and not user-influenceable.
| Endpoint | Purpose | Script | Gated by |
|---|---|---|---|
generativelanguage.googleapis.com |
Gemini image generation (fallback path) | generate_image.py |
API key (env var) |
api.openai.com |
OpenAI image generation (fallback path) | generate_image.py |
API key (env var) |
api.stability.ai |
Stability AI image generation (fallback path) | generate_image.py |
API key (env var) |
api.replicate.com |
Replicate model invocation (fallback path) | generate_image.py |
API key (env var) |
| Replicate-returned result URL | Fetch generated image bytes | generate_image.py |
HTTPS check + SSRF revalidation via url_utils.validate_url (v1.7.0+) |
| User-supplied URLs | Landing page analysis, screenshot capture, page fetch | analyze_landing.py, capture_screenshot.py, fetch_page.py |
DNS-pinned HTTP; browser default-deny unless external egress sandbox is attested, plus per-request validation |
github.com (read-only, via git clone) |
Skill installation | install.sh, install.ps1 |
Hardcoded repo URL |
PyPI (pypi.org, files.pythonhosted.org) |
Python dependency install | install.sh, install.ps1 |
Hardcoded; trusted by pip |
If you discover any other outbound destination not listed above, please report it via the disclosure channel above.
The Boolean --egress-sandbox-attested escape hatch is not supported. Browser
execution accepts only a JSON document conforming to
control-plane/schemas/egress-sandbox-attestation.schema.json and authenticated
with Ed25519. The signature covers the canonical JSON object with
authentication.signature_b64url omitted: UTF-8, lexicographically sorted keys,
no insignificant whitespace, and no ASCII escaping. Attestations must:
- name the
claude-ads-browser-egressaudience and the exact environment; - expire within 24 hours of issuance;
- assert every required IPv4, IPv6, DNS-rebinding, redirect, subresource, metadata, private-address, and fail-closed control;
- include test or policy evidence references; and
- be signed by a key whose public half, key ID, and environment ID are supplied
outside the document through
CLAUDE_ADS_EGRESS_ATTESTATION_PUBLIC_KEY_B64URL,CLAUDE_ADS_EGRESS_ATTESTATION_KEY_ID, andCLAUDE_ADS_EGRESS_ENVIRONMENT_ID.
The runtime receives only the Ed25519 public key, so it cannot manufacture an attestation. Missing dependencies, trust material, controls, evidence, signature, environment binding, or freshness fail closed before Chromium launches. The schema and signature authenticate the issuer's claim; operators must still configure and test the named network boundary independently.
Screenshots and their receipts are confidential. They use same-directory atomic
replacement, receive mode 0600 where POSIX permissions are available, omit the
URL path and query from the receipt, and must not be committed, attached to public
issues, or included in release packages. Capture requires a validated confidential
data-lifecycle contract; receipts contain its lifecycle fields and only
repository/run-relative artifact locators.
Every persisted run and workflow artifact declares the versioned contract in
claude_ads_core/schemas/v1/data-lifecycle.schema.json. The product policy is
control-plane/manifests/data-lifecycle-policy.json. It records classification,
an explicit zero-second product minimum plus an operator-defined purpose-bound
deadline or exception, verified encryption evidence for non-public data, least-
privilege roles, deletion and independent verification, and private incident
handling. These are operational safeguards, not legal retention requirements or
claims of compliance.
Creative-generation JSON stores prompt SHA-256 values and the canonical redacted summary only. Screenshot and generation JSON store relative locators only. Raw prompts, private provider payloads, and resolved local paths remain outside shipped artifacts and should be handled through approved ephemeral/private evidence channels.