Skip to content

feat(aap): In App WAF support for lambda#7783

Open
CarlesDD wants to merge 17 commits into
masterfrom
ccapell/APPSEC-60752/in-app-waf-port
Open

feat(aap): In App WAF support for lambda#7783
CarlesDD wants to merge 17 commits into
masterfrom
ccapell/APPSEC-60752/in-app-waf-port

Conversation

@CarlesDD

@CarlesDD CarlesDD commented Mar 16, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds AppSec support for AWS lambda to dd-trace-js by introducing DC handlers that allow the datadog-lambda-js layer to delegate WAF execution to the tracer.

inappwafport

Changes:

  • New datadog:lambda:start-invocation and datadog:lambda:end-invocation diagnostic channels with its subscribers (appsec/lambdja.js), which maps extracted HTTP data to WAF addresses, run the WAF and reports the results.
  • Reporter adaptation: reportMetrics, reportAttack, reportAttributes, and finishRequest now accept an optional rootSpan parameter, falling back to web.root(req) when not provided. This allows the Lambda handler to pass the span directly since there is no req object in Lambda
  • WAF rootSpan threading: waf/index.js and waf_context_wrapper.js thread rootSpan through the call chain so that keepTrace and reporter calls work correctly for Lambda

Motivation

Porting the In-App WAF security product to AWS Lambda for the Node.js runtime. The Lambda layer extracts HTTP data from the event and dispatches it to the tracer's AppSec domain via DC.

This approach keeps all security logic (WAF execution, attack reporting, trace keep decisions) inside dd-trace-js, and the Lambda layer is only responsible for extracting raw HTTP data and publishing it.

Additional Notes

  • The Lambda channels are always subscribed when AppSec is enabled. They are no-ops unless datadog-lambda-js publishes to them.
  • No new configuration is needed;DD_APPSEC_ENABLED env var controls everything.
  • Serverless defaults in dd-trace-js already neutralize telemetry, remote config, and error logging, so there are no side effects to enabling AppSec in Lambda beyond the WAF initialization cold start cost.
  • This is a monitoring-only first iteration. Blocking, Remote Config, and telemetry are out of scope.
  • Companion PR in datadog-lambda-js: feat(aap): In App WAF support datadog-lambda-js#744

APPSEC-60752

@github-actions

github-actions Bot commented Mar 16, 2026

Copy link
Copy Markdown
Contributor

Overall package size

Self size: 6.26 MB
Deduped: 7.3 MB
No deduping: 7.3 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.0.2 | 85.93 kB | 825.11 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

@codecov

codecov Bot commented Mar 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.73%. Comparing base (68ed9ce) to head (a8d1734).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #7783      +/-   ##
==========================================
- Coverage   93.06%   92.73%   -0.34%     
==========================================
  Files         877      878       +1     
  Lines       50253    50327      +74     
  Branches     9865     9890      +25     
==========================================
- Hits        46770    46670     -100     
- Misses       3483     3657     +174     
Flag Coverage Δ
aiguard-integration-active 41.43% <0.00%> (-0.02%) ⬇️
aiguard-integration-latest 41.45% <0.00%> (+0.11%) ⬆️
aiguard-integration-maintenance 41.52% <0.00%> (-0.01%) ⬇️
aiguard-macos 34.57% <0.00%> (-0.09%) ⬇️
aiguard-ubuntu 34.72% <0.00%> (-0.09%) ⬇️
aiguard-windows 34.39% <0.00%> (-0.09%) ⬇️
apm-capabilities-tracing-macos ?
apm-capabilities-tracing-ubuntu-active 47.96% <9.30%> (+0.09%) ⬆️
apm-capabilities-tracing-ubuntu-latest 47.97% <9.30%> (+0.10%) ⬆️
apm-capabilities-tracing-ubuntu-maintenance 48.01% <9.30%> (?)
apm-capabilities-tracing-ubuntu-oldest ?
apm-capabilities-tracing-windows 47.60% <9.30%> (-0.26%) ⬇️
apm-integrations-aerospike-18-gte.5.2.0 32.99% <0.00%> (-0.09%) ⬇️
apm-integrations-aerospike-20-gte.5.5.0 33.02% <0.00%> (-0.09%) ⬇️
apm-integrations-aerospike-22-gte.5.12.1 33.02% <0.00%> (-0.09%) ⬇️
apm-integrations-aerospike-22-gte.6.0.0 33.02% <0.00%> (-0.09%) ⬇️
apm-integrations-aerospike-eol- 32.92% <0.00%> (-0.09%) ⬇️
apm-integrations-child-process 33.94% <0.00%> (-0.09%) ⬇️
apm-integrations-confluentinc-kafka-javascript-18 40.01% <0.00%> (-0.09%) ⬇️
apm-integrations-confluentinc-kafka-javascript-20 40.02% <0.00%> (-0.09%) ⬇️
apm-integrations-confluentinc-kafka-javascript-22 40.03% <0.00%> (-0.09%) ⬇️
apm-integrations-confluentinc-kafka-javascript-24 39.92% <0.00%> (-0.09%) ⬇️
apm-integrations-couchbase-18 33.18% <0.00%> (+0.07%) ⬆️
apm-integrations-couchbase-eol 33.06% <0.00%> (-0.07%) ⬇️
apm-integrations-dns 32.94% <0.00%> (-0.09%) ⬇️
apm-integrations-elasticsearch 33.96% <0.00%> (-0.09%) ⬇️
apm-integrations-http-latest 41.09% <28.88%> (-0.14%) ⬇️
apm-integrations-http-maintenance 41.16% <28.88%> (-0.16%) ⬇️
apm-integrations-http-oldest 41.10% <28.88%> (-0.15%) ⬇️
apm-integrations-http2 38.30% <0.00%> (?)
apm-integrations-kafkajs-latest 40.11% <0.00%> (+<0.01%) ⬆️
apm-integrations-kafkajs-oldest 40.10% <0.00%> (-0.09%) ⬇️
apm-integrations-net 33.64% <0.00%> (-0.09%) ⬇️
apm-integrations-next-11.1.4 36.64% <ø> (ø)
apm-integrations-next-12.3.7 36.64% <ø> (ø)
apm-integrations-next-13.0.0 28.97% <0.00%> (-0.09%) ⬇️
apm-integrations-next-13.2.0 ?
apm-integrations-next-13.5.11 29.11% <0.00%> (-0.09%) ⬇️
apm-integrations-next-14.0.0 29.04% <0.00%> (-0.09%) ⬇️
apm-integrations-next-14.2.35 29.04% <0.00%> (-0.09%) ⬇️
apm-integrations-next-14.2.6 29.08% <0.00%> (-0.05%) ⬇️
apm-integrations-next-14.2.7 29.08% <0.00%> (-0.05%) ⬇️
apm-integrations-next-15.0.0 29.04% <0.00%> (-0.09%) ⬇️
apm-integrations-next-15.4.0 29.11% <0.00%> (-0.09%) ⬇️
apm-integrations-next-latest 29.15% <0.00%> (-0.09%) ⬇️
apm-integrations-oracledb 33.85% <0.00%> (-0.09%) ⬇️
apm-integrations-prisma-18-gte.6.16.0.and.lt.7.0.0 34.72% <0.00%> (-0.09%) ⬇️
apm-integrations-prisma-latest-all 34.14% <0.00%> (-0.09%) ⬇️
apm-integrations-restify 35.04% <0.00%> (-0.09%) ⬇️
apm-integrations-sharedb 32.35% <0.00%> (-0.09%) ⬇️
apm-integrations-tedious 33.26% <0.00%> (-0.09%) ⬇️
appsec-express 50.86% <38.88%> (-0.16%) ⬇️
appsec-fastify 47.59% <38.88%> (-0.15%) ⬇️
appsec-graphql 47.64% <36.66%> (-0.14%) ⬇️
appsec-integration-active 36.06% <36.66%> (-0.04%) ⬇️
appsec-integration-latest 36.06% <36.66%> (-0.04%) ⬇️
appsec-integration-maintenance 36.12% <36.66%> (-0.04%) ⬇️
appsec-integration-oldest 36.11% <36.66%> (-0.04%) ⬇️
appsec-kafka 40.22% <0.00%> (-0.08%) ⬇️
appsec-ldapjs 39.75% <0.00%> (-0.08%) ⬇️
appsec-lodash 39.67% <0.00%> (-0.08%) ⬇️
appsec-macos 57.28% <100.00%> (+0.01%) ⬆️
appsec-mongodb-core 43.85% <0.00%> (-0.08%) ⬇️
appsec-mongoose 44.70% <0.00%> (-0.09%) ⬇️
appsec-mysql ?
appsec-next-latest-11.1.4 27.27% <0.00%> (-0.08%) ⬇️
appsec-next-latest-12.3.7 27.70% <ø> (ø)
appsec-next-latest-13.0.0 29.07% <0.00%> (-0.09%) ⬇️
appsec-next-latest-13.2.0 ?
appsec-next-latest-13.5.11 29.18% <0.00%> (-0.09%) ⬇️
appsec-next-latest-14.0.0 29.11% <0.00%> (-0.09%) ⬇️
appsec-next-latest-14.2.35 29.11% <0.00%> (-0.09%) ⬇️
appsec-next-latest-14.2.6 29.11% <0.00%> (?)
appsec-next-latest-14.2.7 29.11% <0.00%> (-0.09%) ⬇️
appsec-next-latest-15.0.0 29.11% <0.00%> (-0.09%) ⬇️
appsec-next-latest-latest 29.15% <0.00%> (-0.09%) ⬇️
appsec-next-oldest-11.1.4 27.32% <0.00%> (-0.09%) ⬇️
appsec-next-oldest-12.3.7 29.13% <0.00%> (-0.09%) ⬇️
appsec-next-oldest-13.0.0 29.13% <0.00%> (-0.09%) ⬇️
appsec-next-oldest-13.2.0 29.39% <0.00%> (-0.09%) ⬇️
appsec-next-oldest-13.5.11 ?
appsec-next-oldest-14.0.0 29.42% <0.00%> (-0.09%) ⬇️
appsec-next-oldest-14.2.35 29.42% <0.00%> (-0.09%) ⬇️
appsec-next-oldest-14.2.6 29.42% <0.00%> (-0.09%) ⬇️
appsec-next-oldest-14.2.7 29.42% <0.00%> (-0.09%) ⬇️
appsec-next-oldest-15.0.0 29.42% <0.00%> (-0.09%) ⬇️
appsec-next-oldest-latest 27.90% <ø> (ø)
appsec-node-serialize 38.98% <0.00%> (-0.08%) ⬇️
appsec-passport 42.53% <31.11%> (-0.16%) ⬇️
appsec-postgres 46.60% <36.66%> (-0.15%) ⬇️
appsec-sourcing 38.39% <0.00%> (-0.08%) ⬇️
appsec-stripe 40.38% <31.11%> (-0.15%) ⬇️
appsec-template 39.22% <0.00%> (-0.08%) ⬇️
appsec-ubuntu 57.40% <100.00%> (+0.10%) ⬆️
appsec-windows 57.20% <100.00%> (+0.15%) ⬆️
debugger-ubuntu-active 43.78% <0.00%> (+0.27%) ⬆️
debugger-ubuntu-latest 43.42% <0.00%> (-0.09%) ⬇️
debugger-ubuntu-maintenance 43.91% <0.00%> (+0.27%) ⬆️
debugger-ubuntu-oldest 43.97% <0.00%> (+0.03%) ⬆️
instrumentations-instrumentation-ai 45.33% <ø> (ø)
instrumentations-instrumentation-aws-sdk 44.93% <ø> (ø)
instrumentations-instrumentation-bluebird 27.41% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-body-parser 35.55% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-child_process 33.31% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-cookie-parser 29.31% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-couchbase-18 46.02% <ø> (ø)
instrumentations-instrumentation-couchbase-eol 46.02% <ø> (ø)
instrumentations-instrumentation-crypto 27.46% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-express 29.51% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-express-mongo-sanitize 29.42% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-express-multi-version 41.47% <ø> (ø)
instrumentations-instrumentation-express-session 35.32% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-fastify 47.86% <ø> (ø)
instrumentations-instrumentation-fetch 44.76% <ø> (ø)
instrumentations-instrumentation-fs 27.17% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-generic-pool 27.02% <ø> (ø)
instrumentations-instrumentation-hono 28.62% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-http 37.89% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-http-client-options 37.49% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-kafkajs 48.94% <ø> (ø)
instrumentations-instrumentation-knex 27.40% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-light-my-request 35.18% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-mongoose 28.51% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-multer 35.22% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-mysql2 33.35% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-openai-lifecycle 46.00% <ø> (ø)
instrumentations-instrumentation-otel-sdk-trace 25.27% <ø> (ø)
instrumentations-instrumentation-passport 39.03% <28.88%> (-0.15%) ⬇️
instrumentations-instrumentation-passport-http 38.73% <28.88%> (-0.15%) ⬇️
instrumentations-instrumentation-passport-local 39.18% <28.88%> (-0.15%) ⬇️
instrumentations-instrumentation-pg 33.07% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-promise 27.36% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-promise-js 27.36% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-q 27.39% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-router 43.07% <ø> (ø)
instrumentations-instrumentation-stripe 27.89% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-url 27.29% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-when 27.37% <0.00%> (-0.09%) ⬇️
instrumentations-instrumentation-zlib 27.34% <0.00%> (-0.09%) ⬇️
instrumentations-integration-esbuild-0.16.12-active 24.59% <0.00%> (-0.01%) ⬇️
instrumentations-integration-esbuild-0.16.12-latest 24.59% <0.00%> (-0.01%) ⬇️
instrumentations-integration-esbuild-0.16.12-maintenance 18.57% <ø> (ø)
instrumentations-integration-esbuild-0.16.12-oldest 18.56% <ø> (ø)
instrumentations-integration-esbuild-latest-active 24.59% <0.00%> (-0.01%) ⬇️
instrumentations-integration-esbuild-latest-latest 24.59% <0.00%> (-0.01%) ⬇️
instrumentations-integration-esbuild-latest-maintenance 18.57% <ø> (ø)
instrumentations-integration-esbuild-latest-oldest ?
llmobs-ai 35.07% <0.00%> (-0.08%) ⬇️
llmobs-anthropic 36.45% <0.00%> (-0.09%) ⬇️
llmobs-bedrock 35.97% <0.00%> (-0.08%) ⬇️
llmobs-google-genai 35.73% <0.00%> (-0.08%) ⬇️
llmobs-langchain 34.88% <0.00%> (+0.05%) ⬆️
llmobs-openai-latest ?
llmobs-openai-oldest 39.46% <0.00%> (-0.08%) ⬇️
llmobs-sdk-active 43.41% <0.00%> (-0.09%) ⬇️
llmobs-sdk-latest 43.41% <0.00%> (-0.09%) ⬇️
llmobs-sdk-maintenance 43.52% <0.00%> (-0.09%) ⬇️
llmobs-sdk-oldest 43.50% <0.00%> (-0.09%) ⬇️
llmobs-vertex-ai 35.50% <0.00%> (-0.09%) ⬇️
master-coverage 92.73% <100.00%> (?)
openfeature-macos 37.37% <0.00%> (-0.02%) ⬇️
openfeature-ubuntu 37.51% <0.00%> (-0.02%) ⬇️
openfeature-unit-active 49.95% <ø> (ø)
openfeature-unit-latest 49.95% <ø> (ø)
openfeature-unit-maintenance 50.32% <ø> (ø)
openfeature-unit-oldest 50.32% <ø> (ø)
openfeature-windows 37.25% <0.00%> (+0.03%) ⬆️
platform-core 45.98% <ø> (ø)
platform-esbuild 46.62% <ø> (ø)
platform-instrumentations-misc 29.31% <0.00%> (-0.01%) ⬇️
platform-integration-active 46.63% <0.00%> (-0.02%) ⬇️
platform-integration-latest 46.64% <0.00%> (?)
platform-integration-maintenance 46.73% <0.00%> (-0.02%) ⬇️
platform-integration-oldest 46.89% <0.00%> (-0.01%) ⬇️
platform-shimmer 47.05% <ø> (ø)
platform-unit-guardrails 44.04% <ø> (ø)
platform-webpack 18.10% <ø> (ø)
plugins-aws-durable-execution-sdk-js ?
plugins-axios ?
plugins-azure-cosmos 35.78% <0.00%> (-0.09%) ⬇️
plugins-azure-event-hubs 34.64% <0.00%> (-0.02%) ⬇️
plugins-azure-service-bus 35.12% <0.00%> (-0.02%) ⬇️
plugins-body-parser 36.31% <0.00%> (-0.02%) ⬇️
plugins-bullmq 39.40% <0.00%> (-0.09%) ⬇️
plugins-cassandra 33.47% <0.00%> (-0.09%) ⬇️
plugins-cookie 40.62% <ø> (ø)
plugins-cookie-parser 40.45% <ø> (ø)
plugins-crypto 42.36% <ø> (ø)
plugins-dd-trace-api 33.18% <0.00%> (-0.09%) ⬇️
plugins-express-mongo-sanitize 40.51% <ø> (ø)
plugins-express-session 40.37% <ø> (ø)
plugins-fastify 37.63% <0.00%> (-0.09%) ⬇️
plugins-fetch 33.90% <0.00%> (-0.09%) ⬇️
plugins-fs 33.60% <0.00%> (-0.09%) ⬇️
plugins-generic-pool 39.94% <ø> (ø)
plugins-google-cloud-pubsub 41.28% <0.00%> (-0.09%) ⬇️
plugins-grpc 36.38% <0.00%> (-0.09%) ⬇️
plugins-handlebars 40.51% <ø> (ø)
plugins-hapi 35.45% <0.00%> (-0.09%) ⬇️
plugins-hono 35.78% <0.00%> (-0.09%) ⬇️
plugins-ioredis 34.15% <0.00%> (-0.09%) ⬇️
plugins-jest 27.10% <ø> (ø)
plugins-knex ?
plugins-langgraph 32.20% <0.00%> (-0.09%) ⬇️
plugins-ldapjs 38.96% <ø> (ø)
plugins-light-my-request 40.08% <ø> (ø)
plugins-limitd-client 27.72% <0.00%> (-0.15%) ⬇️
plugins-lodash 40.12% <ø> (ø)
plugins-mariadb 34.98% <0.00%> (-0.09%) ⬇️
plugins-memcached 33.54% <0.00%> (-0.09%) ⬇️
plugins-microgateway-core 34.65% <0.00%> (+<0.01%) ⬆️
plugins-modelcontextprotocol-sdk 32.16% <0.00%> (-0.09%) ⬇️
plugins-moleculer 36.43% <0.00%> (-0.09%) ⬇️
plugins-mongodb 35.59% <0.00%> (-0.09%) ⬇️
plugins-mongodb-core 35.28% <0.00%> (-0.09%) ⬇️
plugins-mongoose 34.17% <0.00%> (-0.09%) ⬇️
plugins-multer 40.42% <ø> (ø)
plugins-mysql 34.47% <0.00%> (-0.09%) ⬇️
plugins-mysql2 34.80% <0.00%> (-0.09%) ⬇️
plugins-nats 36.18% <0.00%> (-0.09%) ⬇️
plugins-node-serialize 40.65% <ø> (ø)
plugins-opensearch 33.41% <0.00%> (-0.09%) ⬇️
plugins-passport-http 40.24% <ø> (ø)
plugins-pino 29.65% <0.00%> (-0.09%) ⬇️
plugins-postgres 34.51% <0.00%> (-0.09%) ⬇️
plugins-process 42.36% <ø> (ø)
plugins-pug 40.62% <ø> (ø)
plugins-redis 34.08% <0.00%> (-0.09%) ⬇️
plugins-router 38.02% <0.00%> (+0.07%) ⬆️
plugins-sequelize ?
plugins-test-and-upstream-amqp10 33.52% <0.00%> (-0.26%) ⬇️
plugins-test-and-upstream-amqplib 39.03% <0.00%> (+0.07%) ⬆️
plugins-test-and-upstream-apollo 34.64% <0.00%> (-0.08%) ⬇️
plugins-test-and-upstream-avsc 33.57% <0.00%> (-0.09%) ⬇️
plugins-test-and-upstream-bunyan 28.86% <0.00%> (-0.09%) ⬇️
plugins-test-and-upstream-connect 36.12% <0.00%> (-0.09%) ⬇️
plugins-test-and-upstream-graphql 35.87% <0.00%> (-0.09%) ⬇️
plugins-test-and-upstream-koa 35.63% <0.00%> (-0.09%) ⬇️
plugins-test-and-upstream-protobufjs 33.80% <0.00%> (-0.09%) ⬇️
plugins-test-and-upstream-rhea 39.00% <0.00%> (-0.09%) ⬇️
plugins-undici ?
plugins-url 42.36% <ø> (ø)
plugins-valkey 33.64% <0.00%> (+0.05%) ⬆️
plugins-vm 42.36% <ø> (ø)
plugins-winston 29.51% <0.00%> (-0.09%) ⬇️
plugins-ws 36.92% <0.00%> (-0.09%) ⬇️
profiling-macos 43.03% <0.00%> (-0.07%) ⬇️
profiling-ubuntu 43.46% <0.00%> (-0.11%) ⬇️
profiling-windows 40.75% <0.00%> (-0.05%) ⬇️
serverless-aws-sdk-latest-aws-sdk 32.91% <0.00%> (-0.09%) ⬇️
serverless-aws-sdk-latest-bedrockruntime 31.81% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-latest-client 36.32% <ø> (ø)
serverless-aws-sdk-latest-dynamodb 33.81% <0.00%> (+<0.01%) ⬆️
serverless-aws-sdk-latest-eventbridge 26.81% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-latest-kinesis 37.00% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-latest-lambda 34.25% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-latest-s3 32.16% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-latest-serverless-peer-service 39.14% <ø> (-0.08%) ⬇️
serverless-aws-sdk-latest-sns ?
serverless-aws-sdk-latest-sqs 37.63% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-latest-stepfunctions 32.82% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-latest-util 46.39% <ø> (ø)
serverless-aws-sdk-oldest-aws-sdk 33.02% <0.00%> (-0.09%) ⬇️
serverless-aws-sdk-oldest-bedrockruntime 31.91% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-oldest-client 36.88% <ø> (ø)
serverless-aws-sdk-oldest-dynamodb 33.91% <0.00%> (-0.06%) ⬇️
serverless-aws-sdk-oldest-eventbridge 26.90% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-oldest-kinesis 37.17% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-oldest-lambda ?
serverless-aws-sdk-oldest-s3 32.29% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-oldest-serverless-peer-service 39.22% <ø> (-0.08%) ⬇️
serverless-aws-sdk-oldest-sns 38.11% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-oldest-sqs 37.71% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-oldest-stepfunctions 32.93% <0.00%> (-0.08%) ⬇️
serverless-aws-sdk-oldest-util 47.13% <ø> (ø)
serverless-azure-durable-functions 36.59% <0.00%> (-0.02%) ⬇️
serverless-azure-functions-eventhubs 38.22% <0.00%> (-0.02%) ⬇️
serverless-azure-functions-servicebus 38.28% <0.00%> (-0.02%) ⬇️
serverless-lambda 34.23% <ø> (-0.10%) ⬇️
test-optimization-cucumber-latest-7.0.0 49.91% <0.00%> (-0.01%) ⬇️
test-optimization-cucumber-latest-latest 52.65% <0.00%> (+0.16%) ⬆️
test-optimization-cucumber-oldest-7.0.0 49.99% <0.00%> (+0.10%) ⬆️
test-optimization-cypress-latest-12.0.0-commonJS 49.19% <0.00%> (-0.01%) ⬇️
test-optimization-cypress-latest-12.0.0-esm 46.12% <0.00%> (-3.00%) ⬇️
test-optimization-cypress-latest-14.5.4-commonJS 47.21% <0.00%> (-1.78%) ⬇️
test-optimization-cypress-latest-14.5.4-esm 47.80% <0.00%> (+0.67%) ⬆️
test-optimization-cypress-latest-latest-commonJS 48.14% <0.00%> (-1.39%) ⬇️
test-optimization-cypress-latest-latest-esm 49.58% <0.00%> (+0.05%) ⬆️
test-optimization-cypress-oldest-12.0.0-commonJS 49.33% <0.00%> (+1.86%) ⬆️
test-optimization-cypress-oldest-12.0.0-esm 49.22% <0.00%> (+1.23%) ⬆️
test-optimization-cypress-oldest-14.5.4-commonJS 46.84% <0.00%> (-2.29%) ⬇️
test-optimization-cypress-oldest-14.5.4-esm 48.06% <0.00%> (+0.23%) ⬆️
test-optimization-jest-latest-latest 55.35% <0.00%> (+0.06%) ⬆️
test-optimization-jest-latest-oldest 52.35% <0.00%> (-1.80%) ⬇️
test-optimization-jest-oldest-latest 55.40% <0.00%> (+0.06%) ⬆️
test-optimization-jest-oldest-oldest 54.28% <0.00%> (+2.00%) ⬆️
test-optimization-mocha-latest-latest 53.59% <0.00%> (+0.06%) ⬆️
test-optimization-mocha-latest-oldest ?
test-optimization-mocha-oldest-latest 53.70% <0.00%> (+0.06%) ⬆️
test-optimization-mocha-oldest-oldest 51.13% <0.00%> (+0.06%) ⬆️
test-optimization-playwright-latest-latest-playwright-active-test-span 44.22% <0.00%> (+0.25%) ⬆️
test-optimization-playwright-latest-latest-playwright-atr 42.85% <0.00%> (+0.09%) ⬆️
test-optimization-playwright-latest-latest-playwright-efd 43.29% <0.00%> (+0.07%) ⬆️
test-optimization-playwright-latest-latest-playwright-final-status 43.36% <0.00%> (+0.11%) ⬆️
test-optimization-playwright-latest-latest-playwright-impacted-tests 42.82% <0.00%> (-0.02%) ⬇️
test-optimization-playwright-latest-latest-playwright-reporting 42.89% <0.00%> (+0.07%) ⬆️
test-optimization-playwright-latest-latest-playwright-test-management 44.49% <0.00%> (-0.14%) ⬇️
test-optimization-playwright-latest-oldest-playwright-active-test-span 44.04% <0.00%> (+0.25%) ⬆️
test-optimization-playwright-latest-oldest-playwright-atr 42.92% <0.00%> (+0.09%) ⬆️
test-optimization-playwright-latest-oldest-playwright-efd 43.20% <0.00%> (+0.05%) ⬆️
test-optimization-playwright-latest-oldest-playwright-final-status 43.26% <0.00%> (?)
test-optimization-playwright-latest-oldest-playwright-impacted-tests 42.74% <0.00%> (?)
test-optimization-playwright-latest-oldest-playwright-reporting 42.70% <0.00%> (+0.07%) ⬆️
test-optimization-playwright-latest-oldest-playwright-test-management 44.44% <0.00%> (+0.08%) ⬆️
test-optimization-playwright-oldest-latest-playwright-active-test-span 44.30% <0.00%> (?)
test-optimization-playwright-oldest-latest-playwright-atr 42.92% <0.00%> (?)
test-optimization-playwright-oldest-latest-playwright-efd 43.35% <0.00%> (+0.07%) ⬆️
test-optimization-playwright-oldest-latest-playwright-final-status 43.44% <0.00%> (+0.07%) ⬆️
test-optimization-playwright-oldest-latest-playwright-impacted-tests 42.90% <0.00%> (-0.02%) ⬇️
test-optimization-playwright-oldest-latest-playwright-reporting 42.94% <0.00%> (+0.07%) ⬆️
test-optimization-playwright-oldest-latest-playwright-test-management 44.57% <0.00%> (+0.07%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-active-test-span 44.12% <0.00%> (+0.25%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-atr 43.01% <0.00%> (+0.09%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-efd 43.28% <0.00%> (+0.07%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-final-status 43.35% <0.00%> (+0.09%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-impacted-tests 42.83% <0.00%> (-0.02%) ⬇️
test-optimization-playwright-oldest-oldest-playwright-reporting 42.76% <0.00%> (+0.07%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-test-management 44.52% <0.00%> (+0.11%) ⬆️
test-optimization-selenium-latest 45.19% <0.00%> (+0.05%) ⬆️
test-optimization-selenium-oldest 45.03% <0.00%> (+0.32%) ⬆️
test-optimization-testopt-active 48.27% <0.00%> (+0.11%) ⬆️
test-optimization-testopt-latest 48.27% <0.00%> (+0.11%) ⬆️
test-optimization-testopt-maintenance 48.25% <0.00%> (+0.12%) ⬆️
test-optimization-testopt-oldest 49.36% <0.00%> (+0.08%) ⬆️
test-optimization-vitest-latest 49.79% <0.00%> (-0.93%) ⬇️
test-optimization-vitest-oldest 47.40% <0.00%> (-0.32%) ⬇️

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

☔ View full report in Codecov by Harness.
📢 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

pr-commenter Bot commented Mar 16, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-06-16 21:02:20

Comparing candidate commit a8d1734 in PR branch ccapell/APPSEC-60752/in-app-waf-port with baseline commit 68ed9ce in branch master.

📊 Benchmarking dashboard

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

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

Unstable benchmarks

These benchmarks have a confidence interval too wide to call a change; treat them as noise rather than signal.

scenario:appsec-appsec-enabled-24

  • unstable execution_time [-149.269ms; +151.779ms] or [-5.690%; +5.786%]

scenario:appsec-appsec-enabled-26

  • unstable execution_time [-170489.224µs; +172331.257µs] or [-6.842%; +6.916%]

scenario:appsec-control-20

  • unstable execution_time [-134.309ms; +132.221ms] or [-7.809%; +7.688%]

scenario:appsec-control-24

  • unstable execution_time [-94.566ms; +90.150ms] or [-7.909%; +7.540%]

scenario:appsec-control-26

  • unstable execution_time [-94273.833µs; +96161.167µs] or [-8.011%; +8.172%]

scenario:dogstatsd-with-tags-20

  • unstable cpu_user_time [-318.703ms; +337.053ms] or [-6.612%; +6.993%]
  • unstable execution_time [-314.545ms; +333.092ms] or [-6.423%; +6.801%]

scenario:plugin-graphql-long-with-depth-and-collapse-off-24

  • unstable cpu_user_time [-395.511ms; +242.604ms] or [-8.882%; +5.448%]
  • unstable execution_time [-420.143ms; +263.735ms] or [-8.866%; +5.566%]
  • unstable max_rss_usage [-51.955MB; +33.468MB] or [-9.548%; +6.151%]

scenario:plugin-graphql-long-with-depth-off-20

  • unstable max_rss_usage [-5.301MB; +13.877MB] or [-3.822%; +10.005%]

scenario:spans-finish-later-26

  • unstable max_rss_usage [-12.433MB; +18.970MB] or [-7.382%; +11.264%]

scenario:test-optimization-large-suite-20

  • unstable max_rss_usage [-4278.223KB; +6216.223KB] or [-5.325%; +7.737%]

@datadog-official

datadog-official Bot commented Mar 16, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

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

Comment thread packages/dd-trace/src/appsec/reporter.js Outdated
Comment on lines +340 to 343
function reportAttack ({ events: attackData, actions }, req, rootSpan) {
if (!req) {
req = storage('legacy').getStore()?.req
}

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'm worried that in this function, if we don't pass the empty object fake "req", it will try to get it from the store, which would make this req variable here undefined, and crash later down the function because it's trying to access props in req (req.socket, req.body, etc).

The safety mecanism that was in place before was the rootSpan check. If req was missing, then rootSpan would also be missing, and thus the if(!rootSpan) return would protect us from undefined req.
But now that we can pass the rootSpan separately from req, this safety check is inoperant. Does that make sense ?

Can you prove to me that req can never be empty here ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yep, your concern is legit: decoupling rootSpan from req breaks the implicit safety mechanism. But in the lambda path, req is never null or undefined in reportAttack (it's an invocationKey ({}), a truthy object flowing from lambda.js). The only place where req is null is in finishRequest.

I've added a test to check the WAF path with a strict req object that throws on any unaudited property access, making it fail if someone adds req.something without a guard in this path.

Comment thread packages/dd-trace/src/appsec/lambda.js
@simon-id

Copy link
Copy Markdown
Member

Overall this PR is a bit scary because it invalidates assumptions that were made during the entire evolution of our codebase. We should really be careful about these changes, a strong test suite, and proactive monitoring. For now I feel like the test suite is a bit light no ?

@CarlesDD CarlesDD force-pushed the ccapell/APPSEC-60752/in-app-waf-port branch from f4de885 to e0b39e1 Compare April 21, 2026 15:05
@CarlesDD

Copy link
Copy Markdown
Contributor Author

Overall this PR is a bit scary because it invalidates assumptions that were made during the entire evolution of our codebase. We should really be careful about these changes, a strong test suite, and proactive monitoring. For now I feel like the test suite is a bit light no ?

Agree this needs careful handling. I've pushed additional changes to strengthen the safety net:

  • More tests for Lambda handler
  • A proxy based WAF path safety test: it fails if anyone adds req.something with no guard in the future
  • Reporter lambda specific test: covering finishRequest and reportAttack with null/empty req
  • JSDocs to make the contract more explicit.

@CarlesDD CarlesDD force-pushed the ccapell/APPSEC-60752/in-app-waf-port branch from c83559f to 590897a Compare April 27, 2026 08:15
@CarlesDD CarlesDD marked this pull request as ready for review April 27, 2026 09:04
@CarlesDD CarlesDD requested a review from a team as a code owner April 27, 2026 09:04

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

Copy link
Copy Markdown

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: 590897a5f9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/dd-trace/src/appsec/lambda.js Outdated
@CarlesDD CarlesDD requested a review from simon-id April 27, 2026 17:20
Comment thread packages/dd-trace/src/appsec/reporter.js Outdated
const persistent = {}

if (path) {
persistent[addresses.HTTP_INCOMING_URL] = path

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

HTTP_INCOMING_URL is expected to be an URL not only the path. There is no way to get the whole URL in lambda?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

HTTP_INCOMING_URL maps to server.request.uri.raw, which is expected to be relative URI (i.e starting at path component, without scheme nor authority components)

Comment thread packages/dd-trace/src/appsec/lambda.js Outdated
}

const invocationKey = {}
span._lambdaAppsecKey = invocationKey

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think we should store extra data in span, we usually create a WeakMap<span,data>.

And I think that you even could use the span itself as "invocationKey"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I agree

Comment thread packages/dd-trace/src/appsec/lambda.js Outdated

waf.disposeContext(invocationKey)

Reporter.finishRequest(null, null, {}, undefined, span)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

shouldn't we send invocationKey as req here to be able to report metrics correctly?

}

if (clientIp) {
persistent[addresses.HTTP_CLIENT_IP] = clientIp

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

add span.setTag(HTTP_CLIENT_IP, clientIp) here and remove first block

Comment thread packages/dd-trace/src/appsec/lambda.js Outdated
persistent[addresses.HTTP_INCOMING_COOKIES] = cookies
}

waf.run({ persistent }, invocationKey, undefined, span)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

invocationKey gonna be always {} no?

Comment thread packages/dd-trace/src/appsec/lambda.js Outdated
persistent[addresses.HTTP_INCOMING_RESPONSE_HEADERS] = filteredHeaders
}

if (Object.keys(persistent).length > 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

let's add a flag and make it true when we have something to add to persistent and then avoid Object.keys(persistent).length > 0.
We should fix this in all our appsec code to avoid the overhead of creating unnecessary objects

if (!rootSpan) {
rootSpan = web.root(req)
}
if (!rootSpan) return

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (!rootSpan) return
if (!req || !rootSpan) return

: '{"triggers":' + attackDataStr + '}'

if (req.socket) {
if (req?.socket) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No need to change it if we check !req before

Suggested change
if (req?.socket) {
if (req.socket) {


rootSpan.addTags(newTags)

if (!req) return

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No need for this it if we check !req before

rootSpan = web.root(req)
}

if (!rootSpan) return

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ditto

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

reportAttributes doesn't use req after getting rootSpan, so the !req guard isn't needed here (unlike reportAttack, which accesses req.socket, web.getContext(req), and req.body after the guard.

There is also an existing test that calls reportAttributes without a req and expects addTags to be called, relying on web.root(undefined) resolving to a span. Adding !req would break that path.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants