Protect applications at runtime by detecting and blocking attacks inside the application itself. Covers RASP architecture, real-time threat detection, virtual patching, behavioral analysis, and the trade-offs between WAF and RASP approaches.
Runtime Application Self-Protection (RASP) is a security mechanism that embeds monitoring and defense logic directly into an application’s runtime environment, enabling it to detect and respond to threats in real time—without relying on external agents or orchestration. It matters when an application must defend itself against attacks that exploit runtime behaviors: SQL injection, command injection, session hijacking, and logic-level vulnerabilities that static analysis or traditional WAFs miss. RASP activates at application startup and runs continuously, observing every request, state change, and system call, and applying defenses that adapt to the current context.
RASP enables applications to introspect their own execution and react to anomalies as they occur. The core pattern is: instrument the application to observe execution and apply defenses based on context, state, and data flow.
This begins with a runtime agent—a library or process that attaches to the application and intercepts key operations. The agent observes:
When a threat is detected, the agent triggers a response: logging, alerting, policy enforcement, or immediate mitigation.
To enable RASP, an application must load a RASP agent at startup. The agent is typically a shared library or module that hooks into the runtime’s execution pipeline.
For a Java application using OpenJDK, the agent is loaded via the JVM’s -javaagent flag:
java -javaagent:/opt/rasp/agent.jar \
-Drasp.policy.file=/etc/rasp/policy.json \
-Drasp.log.level=INFO \
-jar myapp.jar
The agent reads configuration from a JSON file, which defines the rules and behavior:
{
"policies": [
{
"name": "sql-injection-protection",
"trigger": "on-request",
"conditions": [
{
"type": "parameter",
"source": "query",
"name": "username",
"match": "regex",
"value": ".*'[^']*'.*"
},
{
"type": "database-call",
"operation": "executeQuery",
"pattern": "SELECT.*FROM.*WHERE.*username.*=.*"
}
],
"actions": [
{
"type": "block",
"message": "SQL Injection detected in username parameter",
"log": true,
"response": {
"status": 400,
"body": "Bad Request: SQL Injection attack detected"
}
},
{
"type": "alert",
"event": "security-threat",
"severity": "high",
"metadata": {
"attack-type": "sql-injection",
"parameter": "username"
}
}
]
}
],
"tracing": {
"enabled": true,
"max-depth": 10,
"include-exceptions": true
}
}
The agent applies this policy dynamically. On each incoming request, it checks all conditions. If any condition evaluates to true, the actions are executed.
RASP continuously observes database queries and method calls. It detects anomalies by comparing actual behavior against expected patterns.
For example, a web application expects that every login request includes a POST /login with username and password parameters, and executes a SELECT * FROM users WHERE username = ? query.
The agent tracks this pattern and flags deviations:
username = 'admin' OR 1=1 is flagged as suspiciousWhen such a deviation is detected, the agent logs the full execution trace:
{
"timestamp": "2024-03-14T12:34:56.789Z",
"event": "sql-injection",
"request-id": "abc123",
"parameters": {
"username": "admin' OR 1=1--",
"password": "x"
},
"query": "SELECT * FROM users WHERE username = 'admin' OR 1=1--'",
"execution-time": 342,
"database": "PostgreSQL",
"stack-trace": [
"com.example.auth.LoginController.handleLogin()",
"com.example.dao.UserRepository.findUserByUsername()",
"org.postgresql.jdbc.PgPreparedStatement.execute()",
"java.sql.Statement.executeQuery()"
]
}
This trace is available for downstream analysis and alerting.
RASP is especially effective at protecting against logic-level attacks—those that exploit the application’s business logic rather than just its data layer.
Consider an e-commerce application that allows users to update their shipping address. A policy guards against a race condition in the updateShippingAddress endpoint.
The agent monitors the sequence of operations:
validateAddress() and then saveAddress()validateAddress call occurs before saveAddress, and that the same userId is used in both callsIf the agent detects that saveAddress is called with a different userId than validateAddress, it flags a logic inconsistency:
{
"event": "logic-inconsistency",
"policy": "address-update-consistency",
"details": {
"validate-user-id": 42,
"save-user-id": 43,
"timestamp": "2024-03-14T12:35:11.123Z",
"request-id": "xyz789",
"trace": [
"com.example.order.AddressService.updateShippingAddress()",
"com.example.validation.AddressValidator.validateAddress()",
"com.example.storage.AddressRepository.saveAddress()"
]
}
}
The agent can respond by:
RASP does not apply a single policy universally. It adapts to context: user roles, session state, and execution history.
For example, a policy for session hijacking uses multiple criteria:
The agent tracks session state across requests, using a shared session store (e.g., Redis):
{
"session-id": "sess_abc123",
"user-id": 56,
"created": "2024-03-14T12:00:00Z",
"last-active": "2024-03-14T12:34:56Z",
"ip-address": "192.168.1.5",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxx.yyyy"
}
When a request arrives with a session token, the agent checks the session’s current state and compares it to the incoming request. If the IP has changed and the token is old, the agent triggers a session validation step:
GET /api/session/validate?token=...valid: true, reason: "ip-mismatch" or valid: false, reason: "token-expired"If validation fails, the agent:
401 Unauthorized response with a WWW-Authenticate header pointing to a re-authentication endpointsession-hijack-attempt tagRASP relies on configuration that is often subtle and easily misapplied.
A common failure is misaligned policy triggers. A policy may be set to trigger on on-request, but the agent only checks the first request in a session, missing subsequent ones.
To avoid this, the agent supports multiple trigger types:
on-request: for every incoming HTTP requeston-session-start: when a new session is createdon-event: when a specific event occurs (e.g., user-logged-in, database-error)on-periodic: every N seconds, regardless of requestsEach trigger can have independent conditions. For example:
{
"name": "rate-limiting",
"trigger": "on-request",
"conditions": [
{
"type": "request-count",
"interval": "1m",
"threshold": 100,
"window": "sliding"
}
],
"actions": [
{
"type": "throttle",
"delay": 200,
"response": {
"status": 429,
"headers": {
"Retry-After": 200
}
}
}
]
}
This policy throttles requests that exceed 100 in a one-minute sliding window.
A subtle failure occurs when the policy evaluation order is not understood. Conditions are evaluated in sequence, and the first match may short-circuit the rest. A policy may include:
if parameter 'token' existsand if parameter 'token' is validand if user is in role 'admin'But if the agent evaluates parameter 'token' exists and returns true, it may skip the remaining checks—even when token is malformed. To fix this, a full-evaluation mode must be explicitly enabled.
RASP agents often fail silently. A misconfigured policy may not apply, and no logs are visible.
Common silent failures:
javaagent flag is missing or the JAR file is missing from the expected path./etc/rasp/policy.json, but the file is named policy.json and located in /opt/rasp/conf/.policies array is missing, or actions is a string instead of an array.To debug, the agent emits diagnostic logs at startup and runtime:
[INFO] RASP Agent initialized
[INFO] Loading policy from /etc/rasp/policy.json
[ERROR] Failed to parse policy.json: missing required key 'policies'
[WARN] Policy 'sql-injection-protection' not found in file
[INFO] Agent started with 3 policies
[DEBUG] Evaluating condition: parameter 'username' exists
[DEBUG] Found parameter 'username' with value 'admin'' OR 1=1--'
[INFO] Condition matched: 'sql-injection-protection'
The agent also exposes a health endpoint via HTTP:
GET /api/rasp/health
Host: app.example.com
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "healthy",
"agent-version": "1.2.3",
"policies-loaded": 3,
"active-policies": [
"sql-injection-protection",
"session-hijack-detection"
],
"errors": [
"Policy 'rate-limiting' not found",
"Missing configuration key 'tracing.max-depth'"
],
"uptime": "12h34m56s"
}
This endpoint is used by orchestration systems to verify RASP is active and healthy.
RASP agents are deployed as part of the application build or container image.
In a Dockerfile:
FROM openjdk:17-jdk-alpine
COPY myapp.jar /app/myapp.jar
COPY agent.jar /opt/rasp/agent.jar
COPY policy.json /etc/rasp/policy.json
EXPOSE 8080
CMD [
"java",
"-javaagent:/opt/rasp/agent.jar",
"-Drasp.policy.file=/etc/rasp/policy.json",
"-jar", "/app/myapp.jar"
]
The agent is self-contained: it does not require external configuration files to be mounted, but it can load them from the container’s filesystem, from a mounted volume, or from a remote URL.
On startup, the agent checks for a rasp-config.yaml file in the current directory, then in /etc/, and finally in a remote endpoint (http://config.example.com/rasp/config).
If no configuration is found, the agent falls back to default policies:
These defaults ensure that the application is protected even when configuration is missing.
RASP is not a silver bullet. It can fail silently or under load.
max-trace-age setting controls this.In all cases, the agent logs policy version history and execution statistics:
{
"policy": "sql-injection-protection",
"version": "2.1",
"last-updated": "2024-03-14T12:00:00Z",
"executions": 1234,
"matches": 147,
"average-latency": 12.3,
"last-conditions": [
"parameter.username.match",
"database-call.executeQuery.pattern"
]
}
This data is essential for tuning and auditing the RASP system.
Runtime Application Self-Protection is not a tool, but a pattern: instrument the application to observe its own execution and defend against threats in real time. It works by embedding logic into the application’s runtime, allowing it to detect and respond to anomalies with context, state, and data flow. The agent observes requests, calls, and state changes, and applies policies that adapt to the current situation. Configuration is key, and deployment is self-contained. The agent runs continuously, logging, tracing, and reacting. When it fails, it does so silently—so careful attention to diagnostics, health checks, and policy versioning is essential.
This page was rewritten on 16 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy