Back to skill

Security audit

SaySigned - Agreement infrastructure for AI agents

Security checks for vulnerabilities and agentic risk

Overview

This e-signature skill is purpose-aligned but needs Review because it permits agent-driven legally consequential signing and exposes risky bearer-token and credential-handling patterns.

Install only if you are comfortable with an agent handling contract workflows through SaySigned. Require your own approval before every send, sign, decline, void, or billing action; prefer email delivery for human signers; never put access tokens in URLs, logs, prompts, or saved memory; and treat the embedded example API key as exposed and unsafe.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:112
Finding

Live-Format Production API Key Embedded in Documentation

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:198
Finding

Recipient Bearer Tokens May Be Exposed Through URLs and Have No Expiration

Content
View full analysis
Remediation
View remediation

other

Warning
Location
SKILL.md:62
Finding

Legally Consequential Signing Operations Are Permitted Without Transaction-Specific Human Approval

Content
View full analysis
**Human-in-the-loop for config changes.** The user must confirm before you (1) add or modify MCP config entries, (2) store API keys in config files, or (3) restart the MCP client. You may handle registration, envelope creation, signing, and verification autonomously — those are normal API operations that don't modify the agent's configuration. ``` ```text 2. **Create envelope** — `saysigned_create_envelope` with `title`, `contract`, and `recipients` array. 3. **Send envelope** — `saysigned_send_envelope` with the envelope_id. Response includes each recipient's `id` and `access_token`. **Save these — they are needed for signing.** 4. **Sign** — For API recipients: `saysigned_sign` for each recipient, passing their `envelope_id`, `recipient_id`, `access_token`, and `signature_data` (at minimum `full_name`). ``` ### Technical Analysis The Skill requires human confirmation for MCP configuration changes but explicitly permits registration, envelope creation, and signing to occur autonomously. This authorization boundary focuses on local configuration risk while omitting the greater legal and operational consequences of sending or signing a contract. A signature should require transaction-specific authorization based on the final immutable document, signer identity, recipient list, delivery method, and legal authority. A general request to use the Skill does not necessarily authorize every subsequent envelope or every set of generated terms. The absence of a mandatory confirmation checkpoint increases the effect of: - Ambiguous user requests. - Incorrectly generated contract clauses. - Stale or incorrect recipient details. - Untrusted content incorporated from files, templates, or external responses. - Compromised recipient tokens. - Agent mistakes concerning which party it ...[truncated 1426 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (23)

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

The skill instructs the agent to capture and use recipient access tokens for signing. Because these tokens directly authorize recipient actions and the skill promotes autonomous handling, any leakage through logs, prompts, memory, or transcript storage could let an attacker sign or decline on someone else's behalf.

Content

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

md
- **You don't have to use a template.** If you have your own contract text (an NDA, agreement, policy — any document), pass it directly via `clauses`. Templates are a convenience, not a requirement.
- **Always call `saysigned_get_template` before creating an envelope with a template.** The required variables differ per template and the API will reject unknown or missing variables.
- **`saysigned_send_envelope` returns access tokens.** You must capture and use these tokens for signing. They are 128-character hex strings.
- **Signing does not use your API key.** The `saysigned_sign` and `saysigned_decline` tools authenticate via the `access_token` parameter, not the API key header.
- **The envelope auto-completes** when the last recipient signs. You don't need to call a separate "complete" endpoint.
- **Auth header is forwarded automatically.** Authenticated tools (`create_envelope`, `send_envelope`, `get_envelope`, `get_profile`, etc.) use the API key from your MCP client's `Authorization` header. Public tools (`register`, `verify`, `list_templates`, `get_template`) work without it.

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Documenting that send_envelope returns access tokens highlights a real sensitive capability. While the table itself is descriptive, in this skill context it reinforces a workflow where the agent obtains credentials that can be abused for recipient impersonation if not tightly controlled.

Content

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

md
|------|------|-------------|
| `saysigned_register` | None | Register agent, get API key |
| `saysigned_create_envelope` | API key | Create draft envelope |
| `saysigned_send_envelope` | API key | Send for signing, get access tokens |
| `saysigned_get_envelope` | API key | Get envelope details + status |
| `saysigned_void_envelope` | API key | Cancel a sent (not completed) envelope |
| `saysigned_sign` | Access token | Sign as a recipient |

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

Marking the signing tool as authenticated solely by access token means possession of the token is enough to act as the recipient. In an agent setting, that creates a high-risk bearer-credential flow susceptible to misuse, leakage, or confused-deputy behavior.

Content

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

md
| `saysigned_send_envelope` | API key | Send for signing, get access tokens |
| `saysigned_get_envelope` | API key | Get envelope details + status |
| `saysigned_void_envelope` | API key | Cancel a sent (not completed) envelope |
| `saysigned_sign` | Access token | Sign as a recipient |
| `saysigned_decline` | Access token | Decline to sign |
| `saysigned_verify` | None | Verify cryptographic integrity |
| `saysigned_get_audit_trail` | API key | Get hash-chain audit trail |

Credential Access

High
Category
Privilege Escalation
Confidence
92% confidence
Finding

The decline tool is also bearer-token authorized, so leakage or misuse of the token can alter legal workflow by declining on a recipient's behalf. Although lower impact than unauthorized signing, it can still disrupt contracts and business processes.

Content

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

md
| `saysigned_get_envelope` | API key | Get envelope details + status |
| `saysigned_void_envelope` | API key | Cancel a sent (not completed) envelope |
| `saysigned_sign` | Access token | Sign as a recipient |
| `saysigned_decline` | Access token | Decline to sign |
| `saysigned_verify` | None | Verify cryptographic integrity |
| `saysigned_get_audit_trail` | API key | Get hash-chain audit trail |
| `saysigned_list_templates` | None | List available contract templates |

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The skill explicitly states that access tokens are passed as headers or query parameters. Query-parameter support is especially risky because URLs are commonly logged, cached, stored in browser history, and propagated via referrers, increasing the chance of credential disclosure.

Content

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

md
## Key Concepts

- **IDs are UUIDs** — all envelope, recipient, and agent IDs are standard UUIDs (e.g., `2c272d15-cd4b-4c0d-96c0-bd7438b66699`)
- **Access tokens are hex strings** — 128-character hex, passed via `X-Access-Token` header (recommended) or `?access_token=` query parameter
- **API keys start with `ss_live_`** — REST: pass in `X-API-Key` header. MCP: pass as `Authorization: Bearer <key>` (auto-translated)
- **Templates** — use `GET /templates` to discover available templates and `GET /templates/:id` to see required variables
- **Signing order** — all recipients sign in parallel (no enforced order)

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

The documentation states that API delivery returns access tokens for programmatic signing, which is a credential-bearing design. In an agent workflow, this increases risk because the agent may receive secrets that enable legal actions on behalf of recipients.

Content

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

md
Free tier: **5 envelopes/month**, no credit card required. Upgrade: `POST /billing/setup` with `{"plan": "payg"}`.

- **Delivery methods** — `"api"` (default) returns access tokens for programmatic signing; `"email"` sends an invitation email to a human who reviews and gives consent at `doc.saysigned.com`
- **Email recipients** — human recipients authenticate via a URL token in their email link, not an access token. They review the contract in a browser and click "Give Consent" or "Decline"

---

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
Free tier: **5 envelopes/month**, no credit card required. Upgrade: `POST /billing/setup` with `{"plan": "payg"}`.

- **Delivery methods** — `"api"` (default) returns access tokens for programmatic signing; `"email"` sends an invitation email to a human who reviews and gives consent at `doc.saysigned.com`
- **Email recipients** — human recipients authenticate via a URL token in their email link, not an access token. They review the contract in a browser and click "Give Consent" or "Decline"

---

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
Free tier: **5 envelopes/month**, no credit card required. Upgrade: `POST /billing/setup` with `{"plan": "payg"}`.

- **Delivery methods** — `"api"` (default) returns access tokens for programmatic signing; `"email"` sends an invitation email to a human who reviews and gives consent at `doc.saysigned.com`
- **Email recipients** — human recipients authenticate via a URL token in their email link, not an access token. They review the contract in a browser and click "Give Consent" or "Decline"

---

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The send tool definition states that it generates access tokens for API recipients. In the broader skill context, this means the agent can mint or retrieve bearer credentials that allow legal actions, creating a significant impersonation and misuse risk if secrets are exposed or used without authority checks.

Content

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

json
{
  "name": "saysigned_send_envelope",
  "description": "Send a draft envelope for signing. For API recipients, generates access tokens. For email recipients, sends an invitation email with a consent link to doc.saysigned.com (no access_token in response). Consumes 1 envelope (free tier) or reports 1 metered event (paid). Returns 402 if free tier exhausted.",
  "inputSchema": {
    "type": "object",
    "properties": {

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

The security notes acknowledge that access tokens have no expiration. Non-expiring bearer tokens materially increase the blast radius of disclosure because a leaked token can be replayed indefinitely for the duration of the signing flow, especially in systems with verbose logging or retained transcripts.

Content

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

md
- **API keys** are shown once at creation. Store securely. Rotate or delete keys that are no longer needed.
- **Config file security** — API keys stored in MCP config files should have appropriate file permissions. Limit access to the config directory.
- **Access tokens** are per-recipient, per-envelope. Do not reuse. Tokens are 128-character hex strings with no expiration — treat them as secrets for the duration of the signing flow.
- **Webhook secrets** are per-agent. Verify every webhook signature.
- All connections require **TLS** (HTTPS). Verify TLS certificates for `api.saysigned.com`, `mcp.saysigned.com`, and `doc.saysigned.com`.
- API keys are stored as **SHA-256 hashes** — SaySigned never stores plaintext keys.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly says the agent may handle signing autonomously, but signing a contract on behalf of a recipient has legal and business consequences and is not framed with a required user-facing approval or explicit authority check. In this context, the absence of a strong consent/authorization gate could cause an agent to bind a party or apply a signature using an access token without contemporaneous human confirmation.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Step 1 — Register (no auth needed)

bash
curl -s -X POST https://api.saysigned.com/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "My AI Agent", "email": "agent@example.com"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Step 1 — Register (no auth needed)

bash
curl -s -X POST https://api.saysigned.com/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "My AI Agent", "email": "agent@example.com"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Step 1 — Register (no auth needed)

bash
curl -s -X POST https://api.saysigned.com/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "My AI Agent", "email": "agent@example.com"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Step 1 — Register (no auth needed)

bash
curl -s -X POST https://api.saysigned.com/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "My AI Agent", "email": "agent@example.com"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Step 1 — Register (no auth needed)

bash
curl -s -X POST https://api.saysigned.com/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "My AI Agent", "email": "agent@example.com"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Step 1 — Register (no auth needed)

bash
curl -s -X POST https://api.saysigned.com/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "My AI Agent", "email": "agent@example.com"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Step 1 — Register (no auth needed)

bash
curl -s -X POST https://api.saysigned.com/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "My AI Agent", "email": "agent@example.com"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

Step 1 — Register (no auth needed)

bash
curl -s -X POST https://api.saysigned.com/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "My AI Agent", "email": "agent@example.com"}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

The example embeds a live-looking API key directly in documentation and shows it being sent in a request header. Even if intended as a sample, publishing realistic secrets normalizes unsafe handling, risks accidental reuse, and can lead operators or models to copy plaintext credentials into logs, chats, or configs.

Content

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

Use the api_key from step 1 in the X-API-Key header. Use template_id for standard contracts or provide custom clauses.

bash
curl -s -X POST https://api.saysigned.com/envelopes \
  -H "Content-Type: application/json" \
  -H "X-API-Key: ss_live_203bff0e53ba167462aa2cdcbd8e189e2909d37cf76c31da675cb1dba7dc0026" \
  -d '{

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

This example again transmits a live-looking API key in plaintext within documentation. Exposure of an API key can let an attacker create, send, void, or inspect envelopes under the victim account, and examples like this encourage insecure copy/paste and logging practices.

Content

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

This consumes 1 envelope from your quota (free tier) or reports 1 metered event (paid plan). Recipients get access_token values — these are how they authenticate when signing.

bash
curl -s -X POST https://api.saysigned.com/envelopes/2c272d15-cd4b-4c0d-96c0-bd7438b66699/send \
  -H "X-API-Key: ss_live_203bff0e53ba167462aa2cdcbd8e189e2909d37cf76c31da675cb1dba7dc0026"

External Transmission

Medium
Category
Data Exfiltration
Confidence
96% confidence
Finding

The signing example includes a recipient access token directly in the request. These tokens authorize signature actions without an API key, so exposing them in docs, logs, or transcripts could allow unauthorized signing on behalf of that recipient.

Content

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

bash
# Alice signs
curl -s -X POST "https://api.saysigned.com/envelopes/2c272d15-cd4b-4c0d-96c0-bd7438b66699/recipients/62f73ba5-05a0-4223-8f55-e880047a7b3e/sign" \
  -H "Content-Type: application/json" \
  -H "X-Access-Token: 600b9b4297b2921396a1db138a80801c7dfb5101..." \
  -d '{"signature_data": {"full_name": "Alice Chen", "title": "CEO"}}'

External Transmission

Medium
Category
Data Exfiltration
Confidence
96% confidence
Finding

This second signing example similarly exposes a bearer-style recipient access token in a command. Because the token is sufficient to sign, disclosure could directly enable unauthorized contract execution.

Content

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

bash
# Bob signs (last signer → envelope automatically completes with RFC 3161 timestamp)
curl -s -X POST "https://api.saysigned.com/envelopes/2c272d15-cd4b-4c0d-96c0-bd7438b66699/recipients/cc0aeb32-eb9d-420d-ab93-1d42400f85b9/sign" \
  -H "Content-Type: application/json" \
  -H "X-Access-Token: 952340a770b96740e2696c306ad490b28556952e..." \
  -d '{"signature_data": {"full_name": "Bob Smith", "title": "CTO"}}'

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
SKILL.md:140