v0.2.0 · live
CAPFRAME
§ serversandboxfindings.v2

Airtable MCP

npm:airtable-mcp-server@1.13.0

Score
D38
Findings
23
Tools
16
Last scan
2026-06-05

Severity breakdown

Critical0
High8
Medium15
Low0
Info0

Worst finding

Tool `create_record` name implies a side effect that is not declared

· create_record

`create_record` looks like a side-effecting tool (its name contains a mutation verb), but its `side_effects` declaration is []. A policy synthesizer cannot produce safe rules for this tool because it cannot tell what it actually does.

fix: Declare the tool's true side effects explicitly. If the tool is genuinely read-only, rename it to match (e.g. `email.preview` rather than `email.send`).

All 23 findings

  1. high
    Tool `create_record` name implies a side effect that is not declared· create_recordexcessive agency

    `create_record` looks like a side-effecting tool (its name contains a mutation verb), but its `side_effects` declaration is []. A policy synthesizer cannot produce safe rules for this tool because it cannot tell what it actually does.

    fix: Declare the tool's true side effects explicitly. If the tool is genuinely read-only, rename it to match (e.g. `email.preview` rather than `email.send`).

  2. high
    Tool `update_records` name implies a side effect that is not declared· update_recordsexcessive agency

    `update_records` looks like a side-effecting tool (its name contains a mutation verb), but its `side_effects` declaration is []. A policy synthesizer cannot produce safe rules for this tool because it cannot tell what it actually does.

    fix: Declare the tool's true side effects explicitly. If the tool is genuinely read-only, rename it to match (e.g. `email.preview` rather than `email.send`).

  3. high
    Tool `delete_records` name implies a side effect that is not declared· delete_recordsexcessive agency

    `delete_records` looks like a side-effecting tool (its name contains a mutation verb), but its `side_effects` declaration is []. A policy synthesizer cannot produce safe rules for this tool because it cannot tell what it actually does.

    fix: Declare the tool's true side effects explicitly. If the tool is genuinely read-only, rename it to match (e.g. `email.preview` rather than `email.send`).

  4. high
    Tool `create_table` name implies a side effect that is not declared· create_tableexcessive agency

    `create_table` looks like a side-effecting tool (its name contains a mutation verb), but its `side_effects` declaration is []. A policy synthesizer cannot produce safe rules for this tool because it cannot tell what it actually does.

    fix: Declare the tool's true side effects explicitly. If the tool is genuinely read-only, rename it to match (e.g. `email.preview` rather than `email.send`).

  5. high
    Tool `update_table` name implies a side effect that is not declared· update_tableexcessive agency

    `update_table` looks like a side-effecting tool (its name contains a mutation verb), but its `side_effects` declaration is []. A policy synthesizer cannot produce safe rules for this tool because it cannot tell what it actually does.

    fix: Declare the tool's true side effects explicitly. If the tool is genuinely read-only, rename it to match (e.g. `email.preview` rather than `email.send`).

  6. high
    Tool `create_field` name implies a side effect that is not declared· create_fieldexcessive agency

    `create_field` looks like a side-effecting tool (its name contains a mutation verb), but its `side_effects` declaration is []. A policy synthesizer cannot produce safe rules for this tool because it cannot tell what it actually does.

    fix: Declare the tool's true side effects explicitly. If the tool is genuinely read-only, rename it to match (e.g. `email.preview` rather than `email.send`).

  7. high
    Tool `update_field` name implies a side effect that is not declared· update_fieldexcessive agency

    `update_field` looks like a side-effecting tool (its name contains a mutation verb), but its `side_effects` declaration is []. A policy synthesizer cannot produce safe rules for this tool because it cannot tell what it actually does.

    fix: Declare the tool's true side effects explicitly. If the tool is genuinely read-only, rename it to match (e.g. `email.preview` rather than `email.send`).

  8. high
    Tool `create_comment` name implies a side effect that is not declared· create_commentexcessive agency

    `create_comment` looks like a side-effecting tool (its name contains a mutation verb), but its `side_effects` declaration is []. A policy synthesizer cannot produce safe rules for this tool because it cannot tell what it actually does.

    fix: Declare the tool's true side effects explicitly. If the tool is genuinely read-only, rename it to match (e.g. `email.preview` rather than `email.send`).

  9. medium
    Tool `list_records` accepts unconstrained string input· list_recordsunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `filterByFormula`, `tableId`, `view`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  10. medium
    Tool `search_records` accepts unconstrained string input· search_recordsunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `searchTerm`, `tableId`, `view`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  11. medium
    Tool `list_tables` accepts unconstrained string input· list_tablesunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `detailLevel`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  12. medium
    Tool `describe_table` accepts unconstrained string input· describe_tableunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `detailLevel`, `tableId`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  13. medium
    Tool `get_record` accepts unconstrained string input· get_recordunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `recordId`, `tableId`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  14. medium
    Tool `create_record` accepts unconstrained string input· create_recordunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `tableId`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  15. medium
    Tool `update_records` accepts unconstrained string input· update_recordsunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `tableId`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  16. medium
    Tool `delete_records` accepts unconstrained string input· delete_recordsunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `tableId`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  17. medium
    Tool `create_table` accepts unconstrained string input· create_tableunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `description`, `name`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  18. medium
    Tool `update_table` accepts unconstrained string input· update_tableunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `description`, `name`, `tableId`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  19. medium
    Tool `create_field` accepts unconstrained string input· create_fieldunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `tableId`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  20. medium
    Tool `update_field` accepts unconstrained string input· update_fieldunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `description`, `fieldId`, `name`, `tableId`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  21. medium
    Tool `create_comment` accepts unconstrained string input· create_commentunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `parentCommentId`, `recordId`, `tableId`, `text`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  22. medium
    Tool `list_comments` accepts unconstrained string input· list_commentsunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `baseId`, `offset`, `recordId`, `tableId`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

  23. medium
    Tool `upload_attachment` accepts unconstrained string input· upload_attachmentunconstrained input

    The following string parameter(s) have no `maxLength` constraint: `attachmentFieldIdOrName`, `baseId`, `contentType`, `file`, `filename`, `recordId`. Unbounded strings let an attacker stuff arbitrary payloads through the tool, including indirect-injection content.

    fix: Add a `maxLength` to each string property, or constrain with an `enum` or `pattern`. Most legitimate tool inputs fit under a few hundred bytes.

How this was scored

Source sandbox live tools/list captured in an ephemeral Docker container (parameter schemas included → R1/R2/R4 fire). Findings are emitted by the public capframe.findings.v1 schema. Score = 100 − (10·Critical + 4·High + 2·Medium + 1·Low), clamped to [0, 100].

Disagree with a finding? Open an issue.