Skip to content

fix(appsec): Implement limits for analyzed downstream requests#8655

Open
uurien wants to merge 8 commits into
masterfrom
ugaitz/fix-possible-memory-leak
Open

fix(appsec): Implement limits for analyzed downstream requests#8655
uurien wants to merge 8 commits into
masterfrom
ugaitz/fix-possible-memory-leak

Conversation

@uurien
Copy link
Copy Markdown
Collaborator

@uurien uurien commented May 27, 2026

What does this PR do?

Adds limits for downstream HTTP response body collection in the AppSec SSRF path:

  • New config DD_API_SECURITY_MAX_DOWNSTREAM_BODY_BYTES (default 10 MB).
  • Pre-collection guards in http/client.js before buffering the response body:
    • Supported Content-Type only (application/json, text/json, application/x-www-form-urlencoded).
    • Content-Length required and non-zero.
    • Declared Content-Length must not exceed maxBytes.
  • When a guard fails, publishes responseBodyIgnoredReason on apm:http:client:response:finish and skips body collection.
  • AppSec records ignore metrics on the service-entry span and skips WAF body analysis when collection was rejected or on redirects.
  • Unit tests for instrumentation guards, downstream helpers, SSRF wiring, and config.

Motivation

Without limits, a sampled downstream response could buffer unbounded data in memory. This change validates headers before collection and caps the maximum analyzable body size via configuration.

Additional Notes

  • Limits are enforced before attaching body collectors. No streaming-time size checks were added: Node’s HTTP client parser does not expose more bytes than Content-Length.
  • Ignore reasons: content_type_invalid, content_length_missing, content_length_too_big.
  • Response body / guard tests in http.spec.js use a local HTTP server for deterministic headers and body; generic finish-channel tests still hit datadoghq.

System tests

APPSEC-62792

@dd-octo-sts
Copy link
Copy Markdown
Contributor

dd-octo-sts Bot commented May 27, 2026

Overall package size

Self size: 6.05 MB
Deduped: 7.09 MB
No deduping: 7.09 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.0.1 | 82.56 kB | 817.39 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@datadog-official
Copy link
Copy Markdown

datadog-official Bot commented May 27, 2026

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 88.89%
Overall Coverage: 86.50% (-0.00%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: bdf5880 | Docs | Datadog PR Page | Give us feedback!

@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

❌ Patch coverage is 57.14286% with 27 lines in your changes missing coverage. Please review.
✅ Project coverage is 42.90%. Comparing base (c6be3b9) to head (bdf5880).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...ackages/dd-trace/src/appsec/downstream_requests.js 18.18% 18 Missing ⚠️
packages/dd-trace/src/appsec/rasp/ssrf.js 12.50% 7 Missing ⚠️
...ckages/datadog-instrumentations/src/http/client.js 93.93% 2 Missing ⚠️

❌ Your patch check has failed because the patch coverage (57.14%) is below the target coverage (95.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff             @@
##           master    #8655       +/-   ##
===========================================
- Coverage   92.76%   42.90%   -49.86%     
===========================================
  Files         860      538      -322     
  Lines       48708    32570    -16138     
  Branches     9191     3583     -5608     
===========================================
- Hits        45184    13975    -31209     
- Misses       3524    18595    +15071     
Flag Coverage Δ
aiguard-integration-active ?
aiguard-integration-latest ?
aiguard-integration-maintenance ?
aiguard-macos 33.49% <ø> (-0.08%) ⬇️
aiguard-ubuntu ?
aiguard-windows ?
apm-capabilities-tracing-macos ?
apm-capabilities-tracing-ubuntu-active ?
apm-capabilities-tracing-ubuntu-latest ?
apm-capabilities-tracing-ubuntu-maintenance ?
apm-capabilities-tracing-ubuntu-oldest ?
apm-capabilities-tracing-windows ?
apm-integrations-aerospike-18-gte.5.2.0 ?
apm-integrations-aerospike-20-gte.5.5.0 ?
apm-integrations-aerospike-22-gte.5.12.1 ?
apm-integrations-aerospike-22-gte.6.0.0 ?
apm-integrations-aerospike-eol- ?
apm-integrations-child-process ?
apm-integrations-confluentinc-kafka-javascript-18 ?
apm-integrations-confluentinc-kafka-javascript-20 ?
apm-integrations-confluentinc-kafka-javascript-22 ?
apm-integrations-confluentinc-kafka-javascript-24 ?
apm-integrations-couchbase-18 ?
apm-integrations-couchbase-eol ?
apm-integrations-dns ?
apm-integrations-elasticsearch ?
apm-integrations-http-latest ?
apm-integrations-http-maintenance ?
apm-integrations-http-oldest 41.42% <15.87%> (-0.19%) ⬇️
apm-integrations-http2 ?
apm-integrations-kafkajs-latest ?
apm-integrations-kafkajs-oldest ?
apm-integrations-net ?
apm-integrations-next-11.1.4 20.07% <ø> (ø)
apm-integrations-next-12.3.7 20.07% <ø> (ø)
apm-integrations-next-13.0.0 ?
apm-integrations-next-13.2.0 ?
apm-integrations-next-13.5.11 ?
apm-integrations-next-14.0.0 ?
apm-integrations-next-14.2.35 ?
apm-integrations-next-14.2.6 ?
apm-integrations-next-14.2.7 ?
apm-integrations-next-15.0.0 ?
apm-integrations-next-15.4.0 ?
apm-integrations-oracledb ?
apm-integrations-prisma-18-gte.6.16.0.and.lt.7.0.0 ?
apm-integrations-prisma-latest-all ?
apm-integrations-restify ?
apm-integrations-sharedb 32.69% <ø> (-0.08%) ⬇️
apm-integrations-tedious ?
appsec-express ?
appsec-fastify ?
appsec-graphql ?
appsec-integration-active ?
appsec-integration-latest ?
appsec-integration-maintenance ?
appsec-integration-oldest ?
appsec-kafka ?
appsec-ldapjs 39.89% <0.00%> (-0.14%) ⬇️
appsec-lodash 39.94% <0.00%> (?)
appsec-macos ?
appsec-mongodb-core ?
appsec-mongoose ?
appsec-mysql ?
appsec-next-latest-11.1.4 ?
appsec-next-latest-12.3.7 27.69% <ø> (ø)
appsec-next-latest-13.2.0 ?
appsec-next-latest-13.5.11 ?
appsec-next-latest-14.0.0 ?
appsec-next-latest-14.2.6 ?
appsec-next-latest-14.2.7 ?
appsec-next-latest-15.0.0 ?
appsec-next-latest-latest ?
appsec-next-oldest-11.1.4 ?
appsec-next-oldest-12.3.7 ?
appsec-next-oldest-13.0.0 ?
appsec-next-oldest-13.2.0 ?
appsec-next-oldest-13.5.11 ?
appsec-next-oldest-14.0.0 ?
appsec-next-oldest-14.2.35 ?
appsec-next-oldest-14.2.6 ?
appsec-next-oldest-14.2.7 ?
appsec-next-oldest-15.0.0 ?
appsec-next-oldest-latest ?
appsec-node-serialize 39.23% <0.00%> (-0.14%) ⬇️
appsec-passport ?
appsec-postgres ?
appsec-sourcing ?
appsec-stripe ?
appsec-template ?
appsec-ubuntu ?
appsec-windows ?
debugger-ubuntu-active ?
debugger-ubuntu-latest ?
debugger-ubuntu-maintenance ?
debugger-ubuntu-oldest ?
instrumentations-instrumentation-ai 32.35% <ø> (ø)
instrumentations-instrumentation-aws-sdk ?
instrumentations-instrumentation-bluebird 27.74% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-body-parser 35.82% <0.00%> (-0.15%) ⬇️
instrumentations-instrumentation-child_process 33.54% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-cookie-parser 29.61% <0.00%> (-0.13%) ⬇️
instrumentations-instrumentation-couchbase-18 36.81% <ø> (ø)
instrumentations-instrumentation-couchbase-eol ?
instrumentations-instrumentation-crypto 27.82% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-express-mongo-sanitize ?
instrumentations-instrumentation-express-multi-version 20.97% <ø> (ø)
instrumentations-instrumentation-express-session 35.58% <0.00%> (-0.15%) ⬇️
instrumentations-instrumentation-fastify 39.70% <ø> (ø)
instrumentations-instrumentation-fetch 33.05% <ø> (ø)
instrumentations-instrumentation-fs 27.46% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-generic-pool 27.00% <0.00%> (-0.11%) ⬇️
instrumentations-instrumentation-hono 28.90% <0.00%> (-0.13%) ⬇️
instrumentations-instrumentation-http 38.25% <93.93%> (+2.87%) ⬆️
instrumentations-instrumentation-http-client-options 37.71% <0.00%> (-0.16%) ⬇️
instrumentations-instrumentation-kafkajs 48.79% <ø> (ø)
instrumentations-instrumentation-knex 27.73% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-light-my-request 35.43% <0.00%> (-0.14%) ⬇️
instrumentations-instrumentation-mongoose ?
instrumentations-instrumentation-multer 35.50% <0.00%> (-0.15%) ⬇️
instrumentations-instrumentation-mysql2 ?
instrumentations-instrumentation-openai-aiguard 42.77% <ø> (ø)
instrumentations-instrumentation-otel-sdk-trace 25.59% <ø> (ø)
instrumentations-instrumentation-passport 39.28% <15.87%> (-0.18%) ⬇️
instrumentations-instrumentation-passport-http 38.98% <15.87%> (-0.18%) ⬇️
instrumentations-instrumentation-passport-local 39.45% <15.87%> (-0.18%) ⬇️
instrumentations-instrumentation-pg ?
instrumentations-instrumentation-promise 27.69% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-promise-js 27.69% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-q 27.72% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-router 34.98% <ø> (ø)
instrumentations-instrumentation-stripe ?
instrumentations-instrumentation-url 27.65% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-when 27.70% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-zlib 27.70% <ø> (-0.08%) ⬇️
instrumentations-integration-esbuild-0.16.12-active ?
instrumentations-integration-esbuild-0.16.12-latest ?
instrumentations-integration-esbuild-0.16.12-maintenance ?
instrumentations-integration-esbuild-0.16.12-oldest ?
instrumentations-integration-esbuild-latest-active ?
instrumentations-integration-esbuild-latest-latest ?
instrumentations-integration-esbuild-latest-maintenance ?
instrumentations-integration-esbuild-latest-oldest ?
llmobs-ai ?
llmobs-anthropic ?
llmobs-bedrock ?
llmobs-google-genai ?
llmobs-langchain ?
llmobs-openai-latest ?
llmobs-openai-oldest ?
llmobs-sdk-active ?
llmobs-sdk-latest ?
llmobs-sdk-maintenance ?
llmobs-sdk-oldest ?
llmobs-vertex-ai ?
master-coverage 42.90% <57.14%> (?)
openfeature-macos 37.68% <0.00%> (-0.07%) ⬇️
openfeature-ubuntu ?
openfeature-unit-active 50.65% <ø> (ø)
openfeature-unit-latest 50.65% <ø> (ø)
openfeature-unit-maintenance 50.77% <ø> (ø)
openfeature-unit-oldest 50.77% <ø> (ø)
openfeature-windows ?
platform-core 31.85% <ø> (ø)
platform-esbuild 36.42% <ø> (ø)
platform-integration-active ?
platform-integration-latest ?
platform-integration-maintenance ?
platform-integration-oldest ?
platform-shimmer 40.18% <ø> (ø)
platform-unit-guardrails 32.72% <ø> (ø)
platform-webpack 18.08% <0.00%> (-0.03%) ⬇️
plugins-axios ?
plugins-azure-cosmos ?
plugins-azure-event-hubs ?
plugins-azure-service-bus ?
plugins-body-parser ?
plugins-bullmq ?
plugins-cassandra ?
plugins-cookie ?
plugins-cookie-parser ?
plugins-crypto 24.70% <ø> (ø)
plugins-dd-trace-api 33.54% <ø> (-0.08%) ⬇️
plugins-express-mongo-sanitize ?
plugins-express-session ?
plugins-fastify ?
plugins-fetch ?
plugins-fs ?
plugins-generic-pool ?
plugins-google-cloud-pubsub ?
plugins-grpc ?
plugins-handlebars ?
plugins-hapi ?
plugins-hono ?
plugins-ioredis ?
plugins-jest ?
plugins-knex ?
plugins-langgraph 32.51% <ø> (-0.08%) ⬇️
plugins-ldapjs ?
plugins-light-my-request ?
plugins-limitd-client ?
plugins-lodash ?
plugins-mariadb ?
plugins-memcached ?
plugins-microgateway-core ?
plugins-modelcontextprotocol-sdk 32.44% <ø> (-0.08%) ⬇️
plugins-moleculer ?
plugins-mongodb ?
plugins-mongodb-core ?
plugins-multer ?
plugins-mysql ?
plugins-mysql2 ?
plugins-nats ?
plugins-node-serialize ?
plugins-opensearch ?
plugins-passport-http ?
plugins-pino ?
plugins-postgres ?
plugins-process 24.70% <ø> (ø)
plugins-pug ?
plugins-redis ?
plugins-router ?
plugins-sequelize ?
plugins-test-and-upstream-amqp10 ?
plugins-test-and-upstream-apollo ?
plugins-test-and-upstream-avsc 33.97% <ø> (-0.08%) ⬇️
plugins-test-and-upstream-connect ?
plugins-test-and-upstream-graphql ?
plugins-test-and-upstream-koa ?
plugins-test-and-upstream-protobufjs ?
plugins-test-and-upstream-rhea ?
plugins-undici ?
plugins-url ?
plugins-valkey ?
plugins-vm 24.70% <ø> (ø)
plugins-winston ?
plugins-ws ?
profiling-macos ?
profiling-ubuntu ?
profiling-windows ?
serverless-aws-sdk-latest-aws-sdk ?
serverless-aws-sdk-latest-dynamodb ?
serverless-aws-sdk-latest-eventbridge ?
serverless-aws-sdk-latest-kinesis ?
serverless-aws-sdk-latest-lambda ?
serverless-aws-sdk-latest-s3 ?
serverless-aws-sdk-latest-sqs ?
serverless-aws-sdk-latest-stepfunctions ?
serverless-aws-sdk-latest-util ?
serverless-aws-sdk-oldest-aws-sdk ?
serverless-aws-sdk-oldest-bedrockruntime ?
serverless-aws-sdk-oldest-client ?
serverless-aws-sdk-oldest-dynamodb ?
serverless-aws-sdk-oldest-kinesis ?
serverless-aws-sdk-oldest-lambda ?
serverless-aws-sdk-oldest-s3 ?
serverless-aws-sdk-oldest-sns ?
serverless-aws-sdk-oldest-sqs ?
serverless-aws-sdk-oldest-stepfunctions ?
serverless-aws-sdk-oldest-util ?
serverless-azure-durable-functions ?
serverless-azure-functions-eventhubs ?
serverless-azure-functions-servicebus ?
serverless-lambda ?
test-optimization-cucumber-latest-7.0.0 ?
test-optimization-cucumber-latest-latest ?
test-optimization-cucumber-oldest-7.0.0 ?
test-optimization-cypress-latest-12.0.0-commonJS ?
test-optimization-cypress-latest-12.0.0-esm ?
test-optimization-cypress-latest-14.5.4-commonJS ?
test-optimization-cypress-latest-14.5.4-esm ?
test-optimization-cypress-latest-latest-commonJS ?
test-optimization-cypress-latest-latest-esm ?
test-optimization-cypress-oldest-12.0.0-commonJS ?
test-optimization-cypress-oldest-12.0.0-esm ?
test-optimization-cypress-oldest-14.5.4-commonJS ?
test-optimization-cypress-oldest-14.5.4-esm ?
test-optimization-jest-latest-latest ?
test-optimization-jest-latest-oldest ?
test-optimization-jest-oldest-latest ?
test-optimization-jest-oldest-oldest ?
test-optimization-mocha-latest-latest ?
test-optimization-mocha-latest-oldest ?
test-optimization-mocha-oldest-latest ?
test-optimization-mocha-oldest-oldest ?
test-optimization-playwright-latest-latest-playwright-active-test-span ?
test-optimization-playwright-latest-latest-playwright-atr ?
test-optimization-playwright-latest-latest-playwright-efd ?
test-optimization-playwright-latest-latest-playwright-final-status ?
test-optimization-playwright-latest-latest-playwright-impacted-tests ?
test-optimization-playwright-latest-latest-playwright-reporting ?
test-optimization-playwright-latest-latest-playwright-test-management ?
test-optimization-playwright-latest-oldest-playwright-active-test-span ?
test-optimization-playwright-latest-oldest-playwright-atr ?
test-optimization-playwright-latest-oldest-playwright-efd ?
test-optimization-playwright-latest-oldest-playwright-final-status ?
test-optimization-playwright-latest-oldest-playwright-impacted-tests ?
test-optimization-playwright-latest-oldest-playwright-test-management ?
test-optimization-playwright-oldest-latest-playwright-active-test-span ?
test-optimization-playwright-oldest-latest-playwright-atr ?
test-optimization-playwright-oldest-latest-playwright-efd ?
test-optimization-playwright-oldest-latest-playwright-final-status ?
test-optimization-playwright-oldest-latest-playwright-impacted-tests ?
test-optimization-playwright-oldest-latest-playwright-reporting ?
test-optimization-playwright-oldest-latest-playwright-test-management ?
test-optimization-playwright-oldest-oldest-playwright-active-test-span ?
test-optimization-playwright-oldest-oldest-playwright-atr ?
test-optimization-playwright-oldest-oldest-playwright-final-status ?
test-optimization-playwright-oldest-oldest-playwright-impacted-tests ?
test-optimization-playwright-oldest-oldest-playwright-reporting ?
test-optimization-playwright-oldest-oldest-playwright-test-management ?
test-optimization-selenium-latest ?
test-optimization-selenium-oldest ?
test-optimization-testopt-active ?
test-optimization-testopt-latest ?
test-optimization-testopt-maintenance ?
test-optimization-testopt-oldest ?
test-optimization-vitest-latest ?
test-optimization-vitest-oldest ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pr-commenter
Copy link
Copy Markdown

pr-commenter Bot commented May 27, 2026

Benchmarks

Benchmark execution time: 2026-05-29 10:53:56

Comparing candidate commit bdf5880 in PR branch ugaitz/fix-possible-memory-leak with baseline commit c6be3b9 in branch master.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 1496 metrics, 97 unstable metrics.

@uurien uurien added the ai-generated PR created with AI assistance label May 28, 2026
@uurien uurien marked this pull request as ready for review May 29, 2026 10:21
@uurien uurien requested review from a team as code owners May 29, 2026 10:21
@uurien uurien requested review from BridgeAR and bojbrook and removed request for a team May 29, 2026 10:21
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 37afb8fceb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/dd-trace/src/appsec/rasp/ssrf.js Outdated
uurien and others added 2 commits May 29, 2026 12:38
Always run handleRedirectResponse before applying body guard outcomes so
sampled redirect chains still store the Location decision. Skip
response_body_ignored metrics on redirect hops where body analysis is
deferred to the follow-up request.

Co-authored-by: Cursor <cursoragent@cursor.com>
"implementation": "A",
"type": "int",
"internalPropertyName": "appsec.apiSecurity.maxDownstreamBodyBytes",
"default": "10485760"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have to make this configurable? Would a default not be fine?

*/
function getResponseBodyCollectionConfig () {
return {
maxBytes: config?.appsec?.apiSecurity?.maxDownstreamBodyBytes ?? DEFAULT_MAX_DOWNSTREAM_BODY_BYTES,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
maxBytes: config?.appsec?.apiSecurity?.maxDownstreamBodyBytes ?? DEFAULT_MAX_DOWNSTREAM_BODY_BYTES,
maxBytes: config.appsec.apiSecurity.maxDownstreamBodyBytes

If we access the config, it is guaranteed to already have done all of that

return { collect: false, reason: 'content_length_too_big' }
}

return { collect: true }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure but I believe V8 would be able to detect the shape better if we define an object at the top where we just change the value before returning. I would add a undefined reason so the shape stays constant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-generated PR created with AI assistance appsec semver-patch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants