A weblog is a web app that system uses to test the library. It mimics what would be a real instrumented HTTP application. A weblog app is required for each platform that the system tests will test. The weblog must implement a number of different endpoints.
Weblog implementations are located in utils/docker/<language>.
Note: a separate document describes GraphQL Weblog.
This document describes endpoints implemented on weblog. Though, it's not a complete description, and can contain mistakes. The source of truth are the test itself. If a weblog endpoint passes system tests, then you can consider it as ok. And if it does not pass it, then you must correct it, even if it's in line with this document.
You are strongly encouraged to help others by submitting corrections when you notice issues with this document.
All these endpoints must respond 200 unless noted otherwise. If content is not specified, it means that it is not tested. But for coherence, the most used content should be documented.
The response must include the following headers:
content-type: text/plain
content-length: 13
The following text must be written to the body of the response:
Hello world!\n
This endpoint must set the following headers:
content-type: text
content-length: 16
content-language: en-US
Note: The content length must be present, whatever the value as long as it's numeric.
The following text may be written to the body of the response:
Hello headers!\n
This endpoint returns an HTML page instead of a JSON response. It is used to test features that require HTML content, such as RUM (Real User Monitoring) auto-injection.
Important: This is a server-rendered HTML endpoint, not a REST/JSON endpoint. The tracer may inject additional scripts (like the RUM SDK) into the HTML response when RUM injection is enabled.
The response content type must be text/html.
The HTML content must be :
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h1>Hello</h1>
</body>
</html>Note: When RUM injection is enabled via environment variables (DD_RUM_ENABLED=true), the tracer will automatically inject the RUM SDK script into the HTML response.
This endpoint must set the following tags on the local root span:
usr.id
usr.email
usr.name
usr.session_id
usr.role
usr.scope
The value of each tag should be the tag name, for example usr.id should be set to usr.id.
This endpoint must set the following tags on the local root span:
_dd.p.usr_id
The value of _dd.p.usr.id should be dXNyLmlk, which is the base64 encoding of usr.id.
This endpoint must accept a parameter that is a string and is part of the URL path.
The following text may be written to the body of the response:
Hello world!\n
This endpoint must accept a parameter i as an integer.
The following text may be written to the body of the response:
Hello world!\n
This endpoint is used for API security sampling and must accept a parameter i as an integer.
The response status code must be i.
The response body may contain the following text:
Hello!\n
This endpoint is used in conjunction with GET /api_security/sampling/%i for API security sampling and must accept a parameter i as an integer.
The response body may contain the following text:
OK\n
This endpoint tests RFC-1076: API Security sampling fallback behavior when
http.route is absent. The endpoint behavior is controlled by the case query
parameter.
- Query parameter
case: Required. Specifies which test case to execute. Valid values:
-
with_route: Tests that
http.routeis used for sampling when present- Sets:
http.route = "/users/{id}/profile" - Response: 200 OK
- Sets:
-
with_endpoint: Tests fallback to
http.endpointwhenhttp.routeis absent- Sets:
http.endpoint = "/api/products/{param:int}" - Does NOT set:
http.route - Response: 200 OK
- Sets:
-
404: Tests that
http.endpointis NOT used for sampling when status is 404- Sets:
http.endpoint = "/api/notfound/{param:int}" - Does NOT set:
http.route - Response: 404 Not Found
- Sets:
-
computed: Tests on-demand endpoint computation from URL
- Sets:
http.url = "http://localhost:8080/endpoint_fallback_computed/users/123/orders/456" - Does NOT set:
http.routeorhttp.endpoint - Important: The endpoint is computed internally for sampling but must NOT be added as a span tag
- Response: 200 OK
- Sets:
This endpoint is used for downstream requests test, using an addtional component hosting a fastapi application defined in /utils/build/docker/internal_server/app.py
It must open a request on http://internal_server:8089/mirror/{status}{url_extra} with the same method as the method used to call this endpoint (GET, POST, TRACE or PUT).
If a body was sent, it must also be sent to internal_server with the same content type. (whatever is the method used)
All query parameters received must be sent as headers to the internal_server request except for:
statuswhose value must be used in the first path parameter (if status is missing, use200by default)url_extrawhose value must be appended to theinternal_serverurl (if missing, use an empty string)
It must always return a 200 status code.
if the request to internal_server was a success (2xx code), it must return a json body as a map with 3 keys:
statusthe status code of theinternal_serverresponsepayloadthe parsed json content of theinternal_serverreponse body (it can be assumed it's always a json body)headersthe headers of theinternal_serverresponse as a map
if the request to internal_server is a failure, it must return a json body with 2 keys:
statusthe status code of theinternal_serverresponse if available or a null valueerrora string describing the error, for debug purposes
This endpoint tests HTTP redirect chains with downstream requests, using the fastapi application in /utils/build/docker/internal_server/app.py
Query parameters:
totalRedirects: number of redirects (default 0)
The endpoint calls /redirect?totalRedirects={totalRedirects} and follows all 302 redirects until receiving a 200 response.
How it works:
/redirectdecrementstotalRedirectsand redirects to itself untiltotalRedirects=0- When
totalRedirects=0, redirects to/mirror/200which returns 200 OK
Example with totalRedirects=2:
/redirect?totalRedirects=2→ 302/redirect?totalRedirects=1→ 302/redirect?totalRedirects=0→ 302/mirror/200→ 200 OK
Total: 4 downstream requests (totalRedirects + 2).
All query parameters are sent as headers to internal_server requests.
Returns 200 status code.
The endpoint may accept two query string parameters:
repeats- this is the number of spans that should be manually created (default1). Span must be flattened (not nested)garbage- this is the number of tags that should be added to each a span (default1). Tag must be of the formgarbage{i}: Random string,istarting at0
The following text should be written to the body of the response:
Generated {repeats} spans with {garbage} garbage tags\n
Where repeats and garbage are the parameters read from the query string.
The endpoint must accept a query string parameter q. This parameter should be used as part of a query that is executed against a real database (to ensure a database span is created).
The output of the query should be written to the body of the response.
The endpoint must accept a query string parameter code, which should be an integer. This parameter will be the status code of the response message.
This is a generic endpoint. It must accept all methods, all content types, all queries and all sub paths, including empty ones.
The following text should be written to the body of the response:
Hello world!\n
In particular, it accepts and parse JSON and XML content. A typical XML content is :
<?xml version='1.0' encoding='utf-8'?>
<string attack="attr">
content
</string>This endpoint must accept two required parameters (the first is a string, the second is an integer) and are part of the URL path.
Make sure the parameters are name :tag_value and :status_code. Those values are use for the test in tests/appsec/api_security/test_schemas.py
This endpoint must accept all query parameters and all content types.
The first path parameter must be written in the span with the tag appsec.events.system_tests_appsec_event.value and the parameter as value.
The second path parameter must be used as a response status code.
All query parameters (key, value) must be used as (key, value) in the response headers.
The response for this endpoint must be:
Value tagged
There is one exception
The exception was introduced for testing API Security response body
If the first string parameter (:tag_value) starts with payload_in_response_body and the method is POST.
Then the response should contain json with the format:
{"payload": payload}
where payload is the parsed body of the request
Make sure to specify the Content-Type header as application/json
/tag_value/tainted_value/418?Content-Language=fr&custom_field=myvalue
must set the appropriate tag in the span to tainted_value and return a response with the teapot code with response headers populated with Content-Language=fr and custom_field=myvalue.
The goal is to be able to easily test if a request was blocked before reaching the server code or after by looking at the span and also test security rules on response status code or response header content.
This endpoint should set at least one cookie with all security flags (Secure, HttpOnly, SameSite=Strict) to prevent any vulnerabilities from being detected.
This endpoint should set a cookie with all security flags except Secure, to detect only the INSECURE_COOKIE vulnerability.
This endpoint should set a cookie with the name and value coming from the request body (using the cookieName and cookieValue properties), with all security flags except Secure, to detect only the INSECURE_COOKIE vulnerability.
This endpoint should set a cookie with empty cookie value without Secure flag, INSECURE_COOKIE vulnerability shouldn't be detected.
Parameterless endpoint. This endpoint contains a vulnerable source code line (weak hash) in a loop with at least two iterations.
Parameterless endpoint. This endpoint contains 2 different insecure hashing operations (for example md5 and sha1). These operations are located in different points of the executed source code.
The endpoint executes a unique operation of String hashing with secure SHA-256 algorithm
The endpoint executes a unique operation of String hashing with given algorithm name
The endpoint executes a unique operation of String hashing with unsecure MD5 algorithm
Parameterless endpoint. This endpoint contains a hardcoded secret. The declaration of the hardcoded secret should be sufficient to trigger the vulnerability, so returning it in the response is optional.
This endpoint should set at least one cookie with all security flags (Secure, HttpOnly, SameSite=Strict) to prevent any vulnerabilities from being detected.
This endpoint should set a cookie with all security flags except HttpOnly, to detect only the NO_HTTPONLY_COOKIE vulnerability.
This endpoint should set a cookie with empty cookie value without HttpOnly flag, NO_HTTPONLY_COOKIE vulnerability shouldn't be detected.
This endpoint should set a cookie with the name and value coming from the request body (using the cookieName and cookieValue properties), with all security flags except HttpOnly, to detect only the NO_HTTPONLY_COOKIE vulnerability.
This endpoint should set at least one cookie with all security flags (Secure, HttpOnly, SameSite=Strict) to prevent any vulnerabilities from being detected.
This endpoint should set a cookie with all security flags except SameSite=Strict, to detect only the NO_SAMESITE_COOKIE vulnerability.
This endpoint should set a cookie with empty cookie value without SameSite=Strict flag, NO_SAMESITE_COOKIE vulnerability shouldn't be detected.
This endpoint should set a cookie with the name and value coming from the request body (using the cookieName and cookieValue properties), with all security flags except SameSite=Strict, to detect only the NO_SAMESITE_COOKIE vulnerability.
This endpoint should set the header whose name comes in the reflected field of the query string, with the reflected value of another header whose name comes in the origin field of the query string.
Same behaviour as /iast/header_injection/reflected/exclusion but with separate specific cases to obtain a different vulnerability location to avoid deduplication.
This endpoint must contain 15 different vulnerabilities, each on a separate line of code, regardless of their type, to test IAST vulnerability sampling and ensure different hash values are generated.
Exactly the same content as the previous one, in different route and with different vulnerability hashes.
This endpoint must contain 15 different vulnerabilities, each on a separate line of code, regardless of their type, to test IAST vulnerability sampling and ensure different hash values are generated.
Exactly the same content as the previous one, but POST instead of GET and with different vulnerability hashes.
This endpoint must contain 15 different vulnerabilities, each on a separate line of code, regardless of their type, to test IAST vulnerability sampling and ensure different hash values are generated.
This group of endpoints should trigger vulnerabilities detected by IAST with untrusted data coming from certain sources. The used vulnerability is irrelevant. It could be a command injection, SQL injection, or something else.
Warning: Note that each of these endpoints should trigger the vulnerability at a different line in the source code, otherwise, vulnerabilities will be deduplicated. So be careful with refactors.
A GET request using a table query parameter with any value. For example, ?table=users.
A POST request using table as a form parameter with any value.
A GET request using table query parameter name, with any value. The test should retrieve the name itself (without it being hardcoded), and use the name, rather than the value.
A POST request using user form parameter name. See the GET-variant for the implementation.
A GET request using a header table with any value.
A GET request using a header table with any value. It will use its name, without it being hardcoded.
A GET request using a cookie with name table and any value. The value must be used in the vulnerability.
A GET request using a cookie with name table and any value. The name must be used in the vulnerability.
A multipart request uploading a file (with a file name).
A POST request which will receive the following JSON body:
{"name": "table", "value": "user"}
An empty GET request that will execute two database queries, one to get a username and another to do a vulnerable SELECT using the obtained username.
These group of endpoints should trigger vulnerabilities detected by IAST with untrusted data coming from certain sources although the data is validated or sanitized by a configured security control
A post request using a parameter with a value that triggers a vulnerability. The value should be sanitized by a sanitizer security control configured for this vulnerability.
A post request using a parameter with a value that triggers a vulnerability. The value should be sanitized by a sanitizer security control that is not configured for this vulnerability.
A post request using a parameter with a value that triggers a vulnerability. The value should be sanitized by a sanitizer security control configured for all vulnerabilities.
A post request using a parameter with a value that triggers a vulnerability. The value should be validated by an input validator security control configured for this vulnerability.
A post request using a parameter with a value that triggers a vulnerability. The value should be validated by an input validator security control that is not configured for this vulnerability.
A post request using a parameter with a value that triggers a vulnerability. The value should be validated by an input validator security control configured for all vulnerabilities.
A post request using two parameters that triggers a vulnerability. The values should be validated by an input validator security control with an overloaded method configured for all vulnerabilities.
A post request using two parameters that triggers a vulnerability. The values should be validated by an input validator security control with an overloaded method configured for other method signature.
A post request using a parameter with a value that triggers a vulnerability. The value should be sanitized by a sanitizer security control with an overloaded method configured for all vulnerabilities.
A post request using a parameter with a value that triggers a vulnerability. The value should be sanitized by a sanitizer security control with an overloaded method configured for other method signature.
This endpoint accept a mandatory parameter url. It'll make a call to these url, and should return a JSON response :
{
"url": "url", // url in parameter
"status_code": 200, // status code of the response
"request_headers": {}, // request headers as a dict
"response_headers": {} // response headers as a dict
}This endpoint executes database queries for DBM supported libraries. A 200 response is returned if the query is executed successfully.
Expected SQL query:
- For SqlServer:
SELECT @@version - For PostgreSQL & MySQL:
SELECT version()
Expected query params:
integration: Name of DBM supported library- Possible Values:
psycopg
- Possible Values:
operation: Method used to execute database statements- Possible Values:
execute,executemany
- Possible Values:
Supported Libraries:
- Python:
- pyscopg (Python PostgreSQL adapter)
- .NET:
- PHP:
This endpoint executes database queries for DSM supported libraries. A 200 response with message "ok" is returned if the produce and consume calls for the specified tech are started successfully. Otherwise, error messages will be returned.
Expected query params:
integration: Name of messaging tech- Possible Values:
kafka,rabbitmq,sqs,kinesis,sns
- Possible Values:
message: Specific message to produce and consumetopic: Name of messaging topic (if usingintegration=sns)queue: Name of messaging queue (if usingintegration=kafka|rabbitmq|sqs|sns (for sns->sqs tests))stream: Name of messaging stream (if usingintegration=kinesis)exchange: Name of messaging exchange (if usingintegration=rabbitmq)routingKey: Name of message routing key (if usingintegration=rabbitmq)timeout: Timeout in seconds
This endpoint triggers Kafka producer calls.
Expected query params:
topic: Name of the Kafka topic to which the message will be produced.
This endpoint triggers Kafka consumer calls.
Expected query params:
topic: Name of the Kafka topic from which the message will be consumed.timeout: Timeout in seconds for the consumer operation.
This endpoint triggers SQS producer calls.
Expected query params:
queue: Name of the SQS queue to which the message will be produced.message: Specific message to be produced to the SQS queue.
This endpoint triggers SQS consumer calls.
Expected query params:
queue: Name of the SQS queue from which the message will be consumed.timeout: Timeout in seconds for the consumer operation.message: Specific message to be consumed from the SQS queue.
This endpoint triggers SNS producer calls.
Expected query params:
queue: Name of the SQS queue associated with the SNS topic for message production.topic: Name of the SNS topic to which the message will be produced.message: Specific message to be produced to the SNS topic.
This endpoint triggers SNS consumer calls.
Expected query params:
queue: Name of the SQS queue associated with the SNS topic for message consumption.timeout: Timeout in seconds for the consumer operation.message: Specific message to be consumed from the SNS topic.
This endpoint triggers Kinesis producer calls.
Expected query params:
stream: Name of the Kinesis stream to which the message will be produced.timeout: Timeout in seconds for the producer operation.message: Specific message to be produced to the Kinesis stream.
This endpoint triggers Kinesis consumer calls.
Expected query params:
stream: Name of the Kinesis stream from which the message will be consumed.timeout: Timeout in seconds for the consumer operation.message: Specific message to be consumed from the Kinesis stream.
This endpoint triggers RabbitMQ producer calls.
Expected query params:
queue: Name of the RabbitMQ queue to which the message will be produced.exchange: Name of the RabbitMQ exchange to which the message will be produced.routing_key: Name of the RabbitMQ routing key for message production.
This endpoint triggers RabbitMQ consumer calls.
Expected query params:
queue: Name of the RabbitMQ queue from which the message will be consumed.exchange: Name of the RabbitMQ exchange from which the message will be consumed.routing_key: Name of the RabbitMQ routing key for message consumption.timeout: Timeout in seconds for the consumer operation.
This endpoint sets a DSM produce operation manual API checkpoint. A 200 response with "ok" is returned along with the
base64 encoded context: dd-pathway-ctx-base64, which is returned within the response headers. Otherwise, error
messages will be returned.
Expected query params:
type: Type of DSM checkpoint, typically the system name such as 'kafka'target: Target queue name
This endpoint sets a DSM produce operation manual API checkpoint, doing so within another thread to ensure DSM context
API works cross-thread. A 200 response with "ok" is returned along with the base64 encoded context:
dd-pathway-ctx-base64, which is returned within the response headers. Otherwise, error messages will be returned.
Expected query params:
type: Type of DSM checkpoint, typically the system name such as 'kafka'target: Target queue name
This endpoint sets a DSM consume operation manual API checkpoint. The DSM base64 encoded context: dd-pathway-ctx-base64
should be included in the request headers under the _datadog header tag as a JSON formatted string. A 200 response with
text "ok" is returned upon success. Otherwise, error messages will be returned.
Expected query params:
type: Type of DSM checkpoint, typically the system name such as 'kafka'target: Target queue name
This endpoint sets a DSM consume operation manual API checkpoint, doing so within another thread to ensure DSM context
API works cross-thread. The DSM base64 encoded context dd-pathway-ctx-base64 should be included in the request headers
under the _datadog header tag as a JSON formatted string. A 200 response with text "ok" is returned upon success.
Otherwise, error messages will be returned.
Expected query params:
type: Type of DSM checkpoint, typically the system name such as 'kafka'target: Target queue name
This endpoint calls the appsec event tracking SDK function used for user login success.
By default, the generated event has the following specification:
- User ID:
system_tests_user - Metadata:
{metadata0: value0, metadata1: value1}
Values can be changed with the query params called event_user_id.
This endpoint calls the appsec event tracking SDK function used for user login failure.
By default, the generated event has the following specification:
- User ID:
system_tests_user - Exists:
true - Metadata:
{metadata0: value0, metadata1: value1}
Values can be changed with the query params called event_user_id and event_user_exists.
This endpoint calls the appsec event tracking SDK function used for custom events.
By default, the generated event has the following specification:
- Event name:
system_tests_event - Metadata:
{metadata0: value0, metadata1: value1}
Values can be changed with the query params called event_name.
This endpoint calls the v2 of appsec event tracking SDK function used for user login success with the data coming in the request body.
The parameters in the body are:
login: String with the login datauser_id: String with user identifiermetadata: Objet with the metadata
This endpoint calls the v2 of appsec event tracking SDK function used for user login failure with the data coming in the request body.
The parameters in the body are:
login: String with the login dataexists: String with "true" or "false" valuemetadata: Objet with the metadata
This endpoint is supposed to be hit with the necessary headers that are used to create inferred proxy spans for routers such as AWS API Gateway. Not including the headers means a span will not be created by the tracer if the feature exists.
The endpoint supports the following query parameters:
status_code: str containing status code to used in API response
The headers necessary to create a span with example values:
x-dd-proxy-request-time-ms: start time in milliseconds
x-dd-proxy-path: "/api/data",
x-dd-proxy-httpmethod: "GET",
x-dd-proxy-domain-name: "system-tests-api-gateway.com",
x-dd-proxy-stage: "staging",
x-dd-proxy: "aws-apigateway",
This endpoint calls the appsec blocking SDK functions used for blocking users. If the expected parameter matches one of the possible values the WAF will return the proper action.
Expected query parameters:
user: user id.- Possible values:
blockedUser
- Possible values:
This endpoint loads a module/package in applicable languages. It's mainly used for telemetry tests to verify that
the dependencies-loaded event is appropriately triggered.
This endpoint facilitates logging a message using a logging library. It is primarily designed for testing log injection functionality. Weblog apps must log using JSON format.
The following query parameters are optional:
msg: Specifies the message to be logged. If not provided, the default message "msg" will be logged.level: Specifies the log level to be used. If not provided, the default log level is "info".structured: Specifies whether a log message should be generated via a structured or unstructured logger is used. If not provided the default value is True.
This endpoint will create two spans, a parent span (which is a root-span), and a child span.
The spans created are not sub-spans of the main root span automatically created by system-tests, but
they will have the same user-agent containing the request ID in order to allow assertions on them.
The following query parameters are required:
parentName: The name of the parent span (root-span).childName: The name of the child span (the parent of this span is the root-span identified byparentName).
The following query parameters are optional:
shouldIndex: Valid values are1and0. WhenshouldIndex=1is provided, special tags are added in the spans that will force their indexation in the APM backend, without explicit retention filters needed.
This endpoint is used for the Single Spans tests (test_single_span.py).
This endpoint will create two spans, a parent span (which is a root-span), and a child span.
The spans created are not sub-spans of the main root span automatically created by system-tests, but
they will have the same user-agent containing the request ID in order to allow assertions on them.
The following query parameters are required:
parentName: The name of the parent span (root-span).childName: The name of the child span (the parent of this span is the root-span identified byparentName).
The following query parameters are optional:
shouldIndex: Valid values are1and0. WhenshouldIndex=1is provided, special tags are added in the spans that will force their indexation in the APM backend, without explicit retention filters needed.
This endpoint is used for the OTel API tests (test_otel.py). In the body of the endpoint, multiple properties are set on the span to verify that the API works correctly.
To read more about the specific values being used, check test_otel.py for up-to-date information.
This endpoint is used to authenticate a user. Body fields accepted in POST method:
username: the login name for the user.password: password for the user.
It also supports HTTP authentication by using GET method and the authorization header. Additionally, both methods support the following query parameters to use the sdk functions along with the authentication framework:
sdk_trigger: when to call the sdk function,afterorbeforethe automated login event (by defaultafter)sdk_event: login event type:successorfailure.sdk_user: user id to be used in the sdk call.sdk_mail: user's mail to be used in the sdk call.sdk_user_exists:trueoffalseto indicate whether the current user exists and populate the corresponding tag.
This endpoint is used to create a new user. Do not keep the user in memory for later use, only call the framework method to pretend to do so. Body fields accepted in POST method:
username: the login name for the user.password: password for the user.
Additionally, the method supports the following query parameters to use the sdk functions along with the authentication framework:
sdk_event: login event type:signup.sdk_user: user id to be used in the sdk call.sdk_mail: user's mail to be used in the sdk call.
These endpoints are used for the Dynamic Instrumentation tests.
These endpoints will be used for Exception Replay tests.
should rename the trace service, creating a "fake" service
The parameter serviceName is required and should be a string with the name for the fake service
This endpoint is used to spawn a new process and test that shell execution span is properly sent. It supports the following body fields:
command: the program or script to be executed.options: a record with the following options:shell: boolean in order to instruct if the program should be executed within a shell.
args: arguments passed to the program.
This endpoint is OPTIONAL and not related to any test, but to the testing process. When called, it should flush any remaining data from the library to the respective outputs, usually the agent. See more in docs/edit/flushing.md.
This endpoint is used to test for local file inclusion / path traversal attacks, consequently it must perform an operation on a file or directory, e.g. open with a relative path. The chosen operation must be injected with the GET or POST parameter.
Query parameters and body fields required in the GET and POST method:
file: containing the string to inject on the file operation.
The endpoint should support the following content types in the POST method:
application/x-www-form-urlencodedapplication/xmlapplication/json
The chosen operation must use the file as provided, without any alterations, e.g.:
open($file);
Examples:
GET:/rasp/lfi?file=../etc/passwdPOST:{"file": "../etc/passwd"}
This endpoint is used to test for server side request forgery attacks, consequently it must perform a network operation, e.g. an HTTP request. The chosen operation must be partially injected with the GET or POST parameter.
Query parameters and body fields required in the GET and POST method:
domain: containing the string to partially inject on the network operation.
The endpoint should support the following content types:
application/x-www-form-urlencodedapplication/xmlapplication/json
The url used in the network operation should be similar to the following:
http://$domain
Examples:
GET:/rasp/ssrf?domain=169.254.169.254POST:{"domain": "169.254.169.254"}
This endpoint is used to test for SQL injection attacks, consequently it must perform a database query. The chosen operation must be partially injected with the GET or POST parameter.
Query parameters and body fields required in the GET and POST method:
user_id: containing the string to partially inject on the SQL query.
The endpoint should support the following content types:
application/x-www-form-urlencodedapplication/xmlapplication/json
The statement used in the query should be similar to the following:
SELECT * FROM users WHERE id='$user_id';Examples:
GET:/rasp/ssrf?user_id="' OR 1 = 1 --"POST:{"user_id": "' OR 1 = 1 --"}
The idea of this endpoint is to have an endpoint where multiple rasp operation take place. All of them will generate a MATCH on the WAF but none of them will block. The goal of this endpoint is to verify that the rasp.rule.match telemetry entry is updated properly. While this seems easy, the WAF requires that data given on call is passed as ephemeral and not as persistent.
In order to make the test easier, the operation used here need to generate LFI matches. The request will have two get parameters(file1, file2) which will contain a path that needs to be used as the parameters of the chosen lfi function. Then there will be another call to the lfi function with a harcoded parameter '../etc/passwd'. This will make rasp.rule.match to be equal to 3. A code example look like:
lfi_operation($request->get('file1'))
lfi_operation($request->get('file2'))
lfi_operation('../etc/passwd') //This one is harcoded
This endpoint is used to validate DSM context injection injects the correct encoding to a header carrier.
This endpoint is used to validate DSM context extraction works correctly when provided a headers carrier with the context already present within the headers.
This endpoint is used to test ASM Standalone propagation, by calling /returnheaders and returning its value (the headers received) to inspect them, looking for
distributed tracing propagation headers.
Similar to /requestdownstream. This is used to test standalone IAST downstream propagation. It should call /returnheaders and return the resulting json data structure from /returnheaders in its response.
This endpoint returns the headers received in order to be able to assert about distributed tracing propagation headers
The endpoint must accept a query string parameter code, which should be an integer. This parameter will be the status code of the response message, default to 200 OK.
This endpoint is used for client-stats tests to provide a separate "resource" via the endpoint path stats-unique to disambiguate those tests from other
stats generating tests.
Returns a JSON dict, with those values :
{
"status": "ok",
"library": {
"name": "<library's name>", // one of cpp, cpp_nginx, cpp_httpd, dotnet, golang, java, nodejs, php, python, ruby
"version": "1.2.3" // version of the library
}
}This endpoint is used to test for shell injection attacks, consequently it must call a shell command by using a function or method which results in an actual shell being launched (e.g. /bin/sh). The chosen operation must be injected with the GET or POST parameter.
Query parameters and body fields required in the GET and POST method:
list_dir: containing the string to inject on the shell command.
The endpoint should support the following content types in the POST method:
application/x-www-form-urlencodedapplication/xmlapplication/json
The chosen operation must use the file as provided, without any alterations, e.g.:
system("ls $list_dir");
Examples:
GET: `/rasp/shi?list_dir=$(cat /etc/passwd 1>&2 ; echo .)POST:{"list_dir": "$(cat /etc/passwd 1>&2 ; echo .)"}
This endpoint is used to test for command injection attacks by executing a command without launching a shell.
The chosen operation must be injected with the GET or POST parameter.
Query parameters and body fields required in the GET and POST method:
command: containing string or an array of strings to be executed as a command.
The endpoint should support the following content types in the POST method:
application/x-www-form-urlencodedapplication/xmlapplication/json
The chosen operation must use the file as provided, without any alterations, e.g.:
system("$command");
Examples:
GET: `/rasp/cmdi?command=/usr/bin/touch /tmp/passwdPOST:{"command": ["/usr/bin/touch", "/tmp/passwd"]}
This endpoint get a name and a value form the query string, and adds a header Set-Cookie with {name}={value} as header value in the HTTP response
This endpoint is the initial endpoint used to test session fingerprints, consequently it must initialize a new session and the web client should be able to deal with the persistence mechanism (e.g. cookies).
Returns the identifier of the created session id. Example :
c377db41-b664-4e30-af57-5df2e803bec7
Examples:
GET:/session/new
Once a session has been established, a new call to /session/user must be made in order to generate a session fingerprint with the session id provided by the web client (e.g. cookie) and the user id provided as a parameter.
Query parameters required in the GET method:
sdk_user: user id used in the WAF login event triggered during the execution of the request.
Examples:
GET:/session/user?sdk_user=sdkUser
This endpoint is used to test the s3 integration. It creates a bucket if
necessary based on the bucket query parameter and puts an object at the key
query parameter. The body of the object is just the bytes of the key, encoded
with utf-8. Returns a result object with an object JSON object field containing the
e_tag field with the ETag of the uploaded object. The e_tag field has any
extra double-quotes stripped (accounting for a quirk in the boto3 library).
Examples:
GET:/mock_s3/put_object?bucket=somebucket&key=somekey
This endpoint is used to test the s3 integration. It creates a bucket if
necessary based on the original_bucket query parameter and puts an object at
the original_key query parameter. The body of the object is just the bytes of
the key, encoded with utf-8. The method then creates another bucket if
necessary and copies the object into the key location. Returns a result
object with an object JSON object field containing the e_tag field with the
ETag of the copied object. The e_tag field has any extra double-quotes
stripped (accounting for a quirk in the boto3 library).
Examples:
GET:/mock_s3/copy_object?original_bucket=somebucket&original_key=somekey&bucket=someotherbucket&key=someotherkey
This endpoint is used to test the s3 integration. It creates a bucket if
necessary based on the bucket query parameter and puts an object at the key
query parameter. The body of the object is just the bytes of the key, encoded
with utf-8, duplicated enough times to make two multipart uploads. Returns a
result object with an object JSON object field containing the e_tag field
with the ETag of the uploaded object returned by the final
CompleteMultipartUpload call. The e_tag field has any extra double-quotes
stripped (accounting for a quirk in the boto3 library).
Examples:
GET:/mock_s3/multipart_upload?bucket=somebucket&key=somekey
This endpoint is used to test the s3 integration. It creates a bucket if
necessary based on the original_bucket query parameter and puts an object at
the original_key query parameter. The body of the object is just the bytes of
the key, encoded with utf-8. The method then creates another bucket if
necessary and copies the object into the key location. Returns a result
object with an object JSON object field containing the e_tag field with the
ETag of the copied object. The e_tag field has any extra double-quotes
stripped (accounting for a quirk in the boto3 library).
Examples:
GET:/mock_s3/copy_object?original_bucket=somebucket&original_key=somekey&bucket=someotherbucket&key=someotherkey
This endpoint serializes a constant protobuf message. Returns the serialized message as a base64 encoded string. It is meant to be used to test the protobuf serialization integration.
Examples:
GET:/protobuf/serialize
This endpoint deserializes a protobuf message from a base64 encoded string provided in the query parameters. Returns "ok" if deserialization is successful. The simplest way to use it is to pass the output of the /protobuf/serialize endpoint to it. It is meant to be used to test the protobuf deserialization integration.
Expected query params:
msg: Base64 encoded protobuf message to deserialize
Examples:
GET:/protobuf/deserialize?msg=<base64_encoded_message>
This endpoint will be used for Resource Renaming tests, it allows all subpaths.
This endpoint triggers AI Guard SDK evaluations using the evaluate() method from the AI Guard SDK.
Request Format:
- Content-Type:
application/json - Body: List of AI Guard
Messageobjects to be evaluated - Header:
X-AI-Guard-Block(optional, default:false) - Controls whether blocking is enabled
Request Body Example:
[
{
"role": "system",
"content": "You are a helpful AI assistant"
},
{
"role": "user",
"content": "What is the weather like today in New York?"
},
{
"role": "assistant",
"tool_calls": [
{
"id": "call_1",
"function": {
"name": "get_weather",
"arguments": "{ \"location\": \"New York\" }\n"
}
}
]
}
]Response Behavior:
- Success (200 OK): Returns the
Evaluationresult as JSON when evaluation succeeds - Blocked (403 Forbidden): Returns
AIGuardAbortErrorwhen blocking is enabled and content is flagged - Error (500 Internal Server Error): Returns exception details for unexpected errors
Response Examples:
Successful evaluation:
{
"action": "ALLOW",
"reason": "All looks good",
"tags": [],
"tag_probs": {
"jailbreak": 0.0
}
}This endpoint takes a JSON request body, that must be passed directly to the Stripe SDK method that creates a Checkout Session (stripe.checkout.sessions.create() or equivalent).
The object returned by that Stripe SDK method must be returned as JSON in the response body.
If an error happens, the endpoint must respond with a 500 error code.
Important: The SDK should be configured to use the Stripe API mock located at http://internal_server:8089, and use API key sk_FAKE, instead of using the public Stripe API backend.
This endpoint takes a JSON request body, that must be passed directly to the Stripe SDK method that creates a Payment Intent (stripe.paymentIntents.create() or equivalent).
The object returned by that Stripe SDK method must be returned as JSON in the response body.
If an error happens, the endpoint must respond with a 500 error code.
Important: The SDK should be configured to use the Stripe API mock located at http://internal_server:8089, and use API key sk_FAKE, instead of using the public Stripe API backend.
This endpoint acts as a webhook receiver of events sent by the Stripe backend.
It takes a raw (unparsed) request body, and a signature located in header Stripe-Signature, that must be passed directly, along the secret key whsec_FAKE, to the Stripe SDK method that parses webhook events (stripe.webhooks.constructEvent() or equivalent).
The endpoint must return as JSON in the response body, the sub-object event.data.object returned by the constructEvent() Stripe SDK method.
If an error happens, the endpoint must respond with a 403 error code.
This endpoint is implemented by Python, Node.js, and PHP (using openai-php/client).
This endpoint collects interactions with LLMs. The request will have the following query parameters
model: Identifies the LLM model invoked. Examples are:gpt-4.1,gpt-4o-mini,text-davinci-003.operation: Instead of having one each point for each function wrapped, this parameter will be used to decide what method to trigger. The following table maps all operation values to wrapped method: | Value | Python mapped method | Node.js mapped method | PHP mapped method | | --- | --- | --- | --- | |openai-latest-responses.create|OpenAI().responses.create(...)|client.responses.create|$client->responses()->create(...)| |openai-latest-chat.completions.create|OpenAI().chat.completions.create(...)|client.chat.completions.create|$client->chat()->create(...)| |openai-latest-completions.create|OpenAI().completions.create(...)|client.completions.create|$client->completions()->create(...)| |openai-legacy-chat.completions.create|openai.ChatCompletion.create|openai.createChatCompletion|$client->chat()->create(...)| |openai-legacy-completions.create|openai.Completion.create|openai.createCompletion|$client->completions()->create(...)| |openai-async-responses.create|AsyncOpenAI().responses.create(...)| not implemented |$client->responses()->create(...)| |openai-async-chat.completions.create|AsyncOpenAI().chat.completions.create(...)| not implemented |$client->chat()->create(...)| |openai-async-completions.create|AsyncOpenAI().completions.create(...)| not implemented |$client->completions()->create(...)|
For example a call to /llm?model=gpt-4.1&operation=openai-latest-responses.create (URL-encoded) will require that Python does the following call
OpenAI().responses.create(model="gpt-4.1", ...)
This approach makes the endpoint ready to be expanded in the future.
In scenarios that use this endpoint, OPENAI_BASE_URL is set to the system-tests internal server, which mocks the OpenAI API responses.
There are several rules shared between all the existing end-to-end weblogs.
-
Location: Place your weblog in utils/build/docker/<language>/
-
Naming: Use descriptive names like - (e.g., spring-boot, express4, rails70)
-
Structure: Each weblog needs:
utils/build/docker/<language>/ ├── <weblog-name>.Dockerfile # Main Docker configuration ├── <weblog-name>/ # Application source code directory │ ├── app.sh # Startup script │ ├── main.py/app.java/server.js # Main application file │ └── [framework-specific files] # Dependencies, configs, etc. └── install_ddtrace.sh # Shared tracer installation script
- Multi-stage builds: Use when possible for optimization (build → runtime).
- Base images: Use official language images or existing system-tests base images.
- Port: Must expose port 7777 for consistency
- Tracer installation: Always call the install_ddtrace.sh script.
- Environment variables**: Set essential DD environment variables:
ENV DD_TRACE_HEADER_TAGS='user-agent:http.request.headers.user-agent\'
ENV DD_TRACE_INTERNAL_EXIT_ON_FAILURE=true
ENV DD_DATA_STREAMS_ENABLED=true
- Framework + Version: rails70, spring-boot-3-native, express4.
- Special Variants:
- uds-<framework> for Unix Domain Sockets
- <framework>- for specific servers (e.g., spring-boot-undertow).
- <framework>-otel for OpenTelemetry variants.
- Language Consistency: Follow existing patterns in your language folder.