Skip to main content
Datadog Application Security Management (ASM) provides in-app threat detection and protection by instrumenting your running Node.js application. It integrates directly with the tracer to block attacks in real time — no WAF or separate proxy required.

How it works

When AppSec is enabled, dd-trace integrates a Web Application Firewall (WAF) engine into your Node.js process. Every incoming HTTP request is evaluated against Datadog’s managed rule set before your application code runs. If a request matches a known attack pattern, it can be blocked automatically and reported to Datadog.

OWASP Top 10

Detects and blocks SQL injection, XSS, command injection, path traversal, SSRF, and other OWASP Top 10 attacks.

IP & user blocking

Block specific IP addresses or authenticated users via the Datadog UI with no redeployment needed.

RASP

Runtime Application Self-Protection detects exploitation of code-level vulnerabilities in real time.

API Security

Automatically discovers API endpoints and collects schema information to detect shadow or sensitive APIs.

Enabling AppSec

1

Set the environment variable

The simplest way to enable AppSec is via an environment variable:
DD_APPSEC_ENABLED=true node server.js
2

Or enable programmatically

Pass appsec: true (or an options object) to tracer.init():
const tracer = require('dd-trace').init({
  appsec: true,
})
For fine-grained control, pass an options object:
const tracer = require('dd-trace').init({
  appsec: {
    enabled: true,
    rateLimit: 100,         // max attack traces per second (default: 100)
    wafTimeout: 5000,       // WAF execution timeout in microseconds (default: 5000)
    rasp: { enabled: true }, // enable RASP (default: false)
  },
})
3

Verify in Datadog

Open Security > Application Security in Datadog. Detected attacks appear in the Threats explorer within seconds.
AppSec requires a Datadog Agent running alongside your application. The tracer sends security data to the Agent, which forwards it to the Datadog backend.

Configuration options

OptionEnvironment variableDefaultDescription
enabledDD_APPSEC_ENABLEDfalseEnable AppSec
rulesDD_APPSEC_RULESPath to a custom WAF rules file
rateLimitDD_APPSEC_TRACE_RATE_LIMIT100Max attack traces per second
wafTimeoutDD_APPSEC_WAF_TIMEOUT5000WAF execution timeout (microseconds)
rasp.enabledDD_APPSEC_RASP_ENABLEDfalseEnable RASP
apiSecurity.enabledDD_API_SECURITY_ENABLEDtrueEnable API Security schema collection
obfuscatorKeyRegexDD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXPRegex to redact sensitive parameter keys in reports
obfuscatorValueRegexDD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXPRegex to redact sensitive parameter values in reports

AppSec SDK

The tracer.appsec object exposes methods for linking authenticated users to traces, checking blocks, and tracking security-relevant events.

setUser(user)

Links an authenticated user to the current trace. Call this after a user successfully authenticates so that AppSec can correlate requests with user identities for user-blocking rules.
const tracer = require('dd-trace')

app.use((req, res, next) => {
  if (req.user) {
    tracer.appsec.setUser({
      id: req.user.id,
      email: req.user.email,
      name: req.user.displayName,
      role: req.user.role,
    })
  }
  next()
})
The User object accepts the following fields:
FieldTypeRequiredDescription
idstringYesUnique user identifier
emailstringNoUser email address
namestringNoDisplay name
session_idstringNoSession identifier
rolestringNoUser role
scopestringNoOAuth scopes or SAML assertions

isUserBlocked(user)

Checks if the given user matches any active user-blocking rules in Datadog. Returns true if the user should be blocked. If no user is linked to the trace yet, setUser is called internally.
app.post('/login', async (req, res) => {
  const user = await authenticate(req.body)

  if (tracer.appsec.isUserBlocked(user)) {
    tracer.appsec.blockRequest(req, res)
    return
  }

  // proceed with authenticated session
})

blockRequest(req?, res?)

Sends a blocking response to the client based on the request’s Accept header (JSON or HTML) and ends the response. Returns true if blocking was successful.
Stop processing the request immediately after calling blockRequest(). The response has already been sent.
if (tracer.appsec.isUserBlocked(user)) {
  tracer.appsec.blockRequest(req, res)
  return // stop processing
}
If req and res are omitted, the method uses the request objects from the current async context.

trackUserLoginSuccessEvent(user, metadata?) — deprecated

Deprecated. Use tracer.appsec.eventTrackingV2.trackUserLoginSuccess() instead.
Links a successful login event to the current trace.
tracer.appsec.trackUserLoginSuccessEvent(
  { id: 'user-123', email: '[email protected]' },
  { custom_field: 'value' }
)

trackUserLoginFailureEvent(userId, exists, metadata?) — deprecated

Deprecated. Use tracer.appsec.eventTrackingV2.trackUserLoginFailure() instead.

eventTrackingV2

The tracer.appsec.eventTrackingV2 object provides the current recommended API for tracking login events. trackUserLoginSuccess(login, user?, metadata?)
// Login successful
tracer.appsec.eventTrackingV2.trackUserLoginSuccess(
  '[email protected]',      // login key (username, email, etc.)
  { id: 'user-123' },       // optional user object
  { provider: 'google' }    // optional metadata
)
trackUserLoginFailure(login, exists, metadata?)
// Login failed — user exists but wrong password
tracer.appsec.eventTrackingV2.trackUserLoginFailure(
  '[email protected]', // login key
  true,                // whether the user exists
  { reason: 'bad_password' }
)

// Login failed — unknown user
tracer.appsec.eventTrackingV2.trackUserLoginFailure(
  '[email protected]',
  false
)

trackCustomEvent(eventName, metadata?)

Links any custom business-logic event to the current trace. Useful for tracking suspicious activity such as password resets, account modifications, or high-value transactions.
tracer.appsec.trackCustomEvent('payment.high_value', {
  amount: 9999,
  currency: 'USD',
  userId: req.user.id,
})

Supported frameworks

AppSec supports all major Node.js HTTP frameworks that dd-trace instruments, including:
  • Express
  • Fastify
  • Hapi
  • Koa
  • NestJS (via Express or Fastify adapter)
  • Next.js
  • Restify
  • Connect

Blocking response templates

By default, dd-trace returns a built-in HTML or JSON response when blocking a request. You can supply custom templates:
tracer.init({
  appsec: {
    enabled: true,
    blockedTemplateHtml: '/path/to/blocked.html',
    blockedTemplateJson: '/path/to/blocked.json',
  },
})
Or via environment variables:
DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML=/path/to/blocked.html
DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON=/path/to/blocked.json

Build docs developers (and LLMs) love