Skip to content

fix: apify-api-read/write coerce query values before validation #1716

Description

@jirispilka

apify-api-write (src/tools/api/apify_api_write.ts:116) and apify-api-read (src/tools/api/apify_api_read.ts:48) validate with compileSchema, the shared AJV instance with coerceTypes: 'array'. The query schema is record<string, string | number | boolean>, so AJV changes invalid values into valid ones and does not reject them:

  • {"query": {"deleteAll": null}} is sent as deleteAll= (null becomes "")
  • {"query": {"limit": [10]}} is sent as limit=10 (a one-item array becomes a scalar)

The call should fail input validation instead.

send-server-actor-request (#1681) already avoids this with its own new Ajv({ coerceTypes: false, ... }). Do the same for both API tools, or add a non-coercing compileSchema variant in src/utils/ajv.ts. Add a unit test for each tool to show that null and array query values are rejected.

Found in review of #1681.

Verified on master 4345570 (2026-10-28)

Reproduced with a unit test that captures the outgoing request:

  • apify-api-read {"path":"/v2/datasets","query":{"limit":[10],"desc":null}} is sent as https://api.apify.com/v2/datasets?limit=10&desc=
  • apify-api-write {"path":"/v2/datasets/abc","method":"DELETE","query":{"deleteAll":null,"limit":[10]}} is sent as https://api.apify.com/v2/datasets/abc?deleteAll=&limit=10

[10] becomes the string "10" (the string branch of the union is tried first); the URL is the same. send_server_actor_request.ts:490 rejects both values.

Notes for the fix:

  • A non-coercing variant in src/utils/ajv.ts must keep the removeKeyword('pattern' | 'patternProperties' | 'format') hardening from ajv.ts:15-17.
  • Don't switch send-server-actor-request to the new helper in this PR.
  • With coercion off, a non-string path (e.g. 123) is also rejected instead of becoming "123". That is expected.
  • Tests: ajvValidate returns false for query: {x: null} and query: {x: [10]} on each tool, and a valid query: {limit: 10, desc: true, format: 'json'} still passes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

low priorityLow priority issues to be done eventually.t-aiIssues owned by the AI team.

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions