Skip to content

Release Notes

#164 · Email-Based Authentication: Cover Logins Behind Email OTPs

Availability: General Availability

Many apps send a one-time code or a magic link by email at sign-in. Until now, that single step was enough to keep an authenticated DAST scan stuck at the login page. Escape now provisions managed scan email addresses the scanner reads on its own, so the rest of your application finally becomes testable end-to-end.

What's New

  • Managed scan inboxes: Escape provisions email addresses under @scan.escape.tech tied to your organization, so you don't have to share a real inbox with the scanner.
  • Email OTP support: the scanner waits for the email, extracts the verification code, and types it into the login form without manual help.
  • Magic link support: when the app sends a clickable sign-in link, the scanner follows it the way a real user would.
  • Works with the Agentic Browser: plain-language instructions are enough, and they're even optional. The AI browser detects the email step on its own.

Why It Matters

Email-gated logins are everywhere: SaaS portals, internal admin consoles, and any flow built around passwordless sign-in. Without managed inboxes, AppSec teams either kept these apps out of scope or fell back on test accounts with static codes, leaving real authenticated paths untested. Now that Escape reads the inbox for you, you don't lose coverage every time an app sends a code by email, and authenticated business-logic findings surface where they actually hide: behind the login.

How to Get Started

  • Pick a scan email address: <alias>.<your-org-id-first-segment>@scan.escape.tech. You'll find your organization ID on the Organization general settings page.
  • Reference it as the username in your authentication preset. With the Agentic Browser, plain-language instructions handle the rest. With Browser Actions, use fill_email_totp for codes or click_mail_magic_link for magic links.

Learn More

Questions?

Have a question? Reach out on your dedicated support channel (Slack, Microsoft Teams, or whichever channel we've set up with your team), or email us at support@escape.tech.

#163 · Asset Project IDs in the Escape Public API and CLI

Availability: General Availability. Discover project IDs on every asset response in Escape's public API and CLI: map findings to your portal without extra round trips.

You can already assign assets to projects on writes. Reads stayed silent: asset payloads came back without their project assignments, so anything round-tripping through the API or escape-cli had to call /v3/projects separately to place findings in the right product bucket. Asset payloads now carry projectIds on every read endpoint, and GET /v3/assets accepts a projectIds filter for parity with /v3/scans.

What's New

  • projectIds on every asset payload: returned by GET /v3/assets, GET /v3/assets/:assetId, and every endpoint that embeds an asset (issues, profiles, events, scan issues). Empty array when no project is assigned, never null.
  • projectIds filter on GET /v3/assets: ?projectIds=A,B scopes a list to assets in any of those projects, mirroring the semantics already on /v3/scans.
  • escape-cli assets list --project-id <uuid>: repeatable flag plumbed through to the same filter.
  • PROJECTS count column in escape-cli assets list and escape-cli assets get table output. JSON output is unchanged and now includes the full projectIds array.

Why It Matters

Customer AppSec teams plugging Escape into their internal product portals told us they were running extra /v3/projects lookups just to figure out which product each issue belonged to. That's a small tax that adds up across thousands of findings. Round-tripping is now lossless: write projectIds on an asset, read them straight back. Pipelines consuming issues, profiles, or events get the project context on the first response, so you can route findings into the right bucket without a second hop.

How to Get Started

  • API: read projectIds from any asset response. Filter lists with GET /v3/assets?projectIds=<uuid>,<uuid>.
  • CLI: escape-cli assets list --project-id <uuid> -o json scopes the list. escape-cli assets get <id> -o json includes projectIds on every detail payload.
  • SDKs: regenerate from services/public-api/v3.openapi.json to pick up the new field and query parameter.

Compatibility

Hard-Breaking Changes

None.

Soft-Breaking Changes

  • Public API and CLI assets list and assets get table columns: a new PROJECTS count column sits between OWNERS and NAME. Scripts that parse the human-readable table by tab-column index need to shift their NAME index by one. JSON output (-o json) is unchanged and is the recommended target for automation.

Non-Breaking Changes

  • projectIds: string[] on AssetSummarized and AssetDetailed: present on every asset returned by the public API, including embedded assets in issues, profiles, events, and scan issues. SDKs that ignore unknown response keys keep working unchanged.
  • projectIds query parameter on GET /v3/assets: optional, comma-separated, OR semantics. Existing callers that don't pass it see no change.
  • --project-id flag on escape-cli assets list: new optional flag, repeatable. Existing invocations are unaffected.

Questions?

Have a question? Reach out on your dedicated support channel (Slack, Microsoft Teams, or whichever channel we've set up with your team), or email us at support@escape.tech.

TLDR: General Availability: Discover how AI agents can now list DAST schemas with signed URLs and jump from any issue to its latest events in one Public API call.

AI agents that drive DAST through Escape's Public API used to lose two hops on the most basic questions: "where's the schema for this profile?" and "what events produced this issue?". Starting today, the profile detail carries the schema's signed URL alongside its metadata, and the issue detail links straight to the latest events from the scan that surfaced it. The CLI ships matching one-command wrappers so an agent can go from profile to schema, or from issue to full request-response evidence, in a single call.

What's New

  • Schemas on the profile detail: GET /v3/profiles/:profileId now returns signedUrl and isActive on every extraAssets[] entry. No more re-fetching each asset just to get a download link.
  • Issue to events link on the issue detail: GET /v3/issues/:issueId now returns latestEventIds (up to five, newest-first, from the issue's last-seen scan) and latestEventsTruncated so agents know when to paginate.
  • One CLI command per intent:
    • escape-cli profiles get-schema <profile-id> prints the active schema's metadata; add -f <file> to download the bytes via the signed URL in the same call.
    • escape-cli profiles upload-schema <profile-id> --file <path> uploads, creates the schema asset, and attaches it to the profile in one shot.
    • escape-cli issues get-with-events <issue-id> hydrates every latest event, including the full request-response Exchange, in a single MCP tool call.

Why It Matters

Customers who drive Escape at scale do it programmatically, and the feedback we hear most often on customer calls is consistent: agents and CI pipelines want handy commands that wrap multiple steps, not granular flows that mirror the database. Getting a schema used to take two round trips per asset. Attaching a freshly uploaded schema to a profile used to take three different surfaces, one of them undocumented. Navigating from an issue to the events that produced it used to require knowing the event IDs up front.

That's fixed. An agent can now go from a profile id to a downloadable schema in one call, and from an issue id to the actual request-response evidence in one MCP tool call. Triage gets shorter. CI jobs get simpler. MCP-powered tools get to answer real questions instead of stitching together two or three lookups.

The changes land on the detail endpoints only. List endpoints stay unchanged, so there's no fan-out on GET /v3/profiles or GET /v3/issues, no per-profile signed-URL minting on list calls, and no surprise cost or exposure bump for callers that page through collections.

How to Get Started

No flag, no toggle, no configuration: both changes are on for every organization.

  • Public API: fetch a profile with GET /v3/profiles/:profileId and read the new signedUrl and isActive fields on each extraAssets[] entry (signedUrl is non-null only for class === 'SCHEMA'). Fetch an issue with GET /v3/issues/:issueId and read latestEventIds and latestEventsTruncated; hydrate each event with GET /v3/events/:id to get the Exchange.
  • CLI: upgrade to the latest escape-cli. The new commands are profiles get-schema, profiles upload-schema, and issues get-with-events. The existing escape-cli issues get table also gains a LATEST EVENTS column.
  • MCP: the Escape MCP server picks up issues_get_with_events automatically, so agents get the one-call hydration path without any configuration.

Compatibility

Scoped to the Public API wire contract and OpenAPI spec.

Hard-breaking changes

None.

Soft-breaking changes

Wire payloads and HTTP status codes are unchanged. Regenerated SDKs and strongly-typed consumers will see new optional fields.

  • GET /v3/profiles/:profileId response: ProfileExtraAsset now includes two additive fields, signedUrl (nullable string, non-null only for class === 'SCHEMA') and isActive (boolean). Regenerated SDKs expose new accessors. Existing hand-written parsers keep working; the fields are additive.
  • GET /v3/issues/:issueId response: IssueDetailed gains two optional fields, latestEventIds (array of opaque string IDs, GraphQL ID scalars, not guaranteed UUIDs, maximum five, newest-first) and latestEventsTruncated (boolean). Because IssueDetailed is reused inside EventDetailed.issues[], strongly-typed SDK consumers of GET /v3/events/:id will see the typed surface widen. The wire payload of GET /v3/events/:id stays byte-identical: the route never sets these fields.

Non-breaking changes

  • List endpoints untouched: GET /v3/profiles and GET /v3/issues return the same payloads as before. The enrichment is deliberately scoped to the single-resource detail endpoints to avoid fan-out.
  • No new routes, no authentication changes, no status-code changes, no new top-level resource group. Schemas remain modeled as assets.

What's Next?

Regular improvements to the Public API and the CLI, guided by what we hear on customer calls.

Learn More

Questions?

Have a question? Reach out on your dedicated support channel (Slack, Microsoft Teams, or whichever channel we've set up with your team), or email us at support@escape.tech.

#161 · Public API: Clearer Error Types in Generated SDKs

Availability: General Availability

Error responses across the Escape Public API (v3) now carry explicit, semantic schema names. Every endpoint returns the same JSON payloads it always did, so direct HTTP integrations need no changes. If you regenerate an SDK from the updated OpenAPI spec, you'll see a handful of error-type renames that make decoded errors easier to read and reuse.

What's New

  • Named error schemas: the 400, 404, 409, and 500 responses now expose BadRequest, PaginationError, NotFound, Conflict, and InternalServerError as semantic schema names in the spec.
  • Consistent types across endpoints: regenerated SDKs use one semantic type per error shape, so you can share error-handling code across every endpoint that returns the same error.
  • Spec matches reality on GET /scans/{scanId}/targets: the declared 400 schema is now a single PaginationError, matching what the server actually returns.

Why It Matters

Until today, SDKs generated from our spec produced awkward error types like ListProfiles400Response or UpdateProfile400Response, one per operation, even when the payload was identical. Writing shared error-handling meant juggling a dozen near-duplicate types. With semantic names, one handler can cover every list endpoint's pagination error, another can cover every validation error, and so on. AppSec tooling that wraps the SDK ends up with cleaner imports, fewer surprises during audits, and fewer places to update when a new endpoint shows up.

How to Get Started

  • Call the API directly with JSON: nothing to do. Payloads are byte-for-byte identical.
  • Use an SDK and don't regenerate: nothing to do.
  • Use an SDK and regenerate from the new spec: update imports to the new type names. See the Compatibility section below for the exact renames.

Compatibility

Hard-breaking changes

None.

Soft-breaking changes

Wire payloads and HTTP status codes are unchanged. Regenerated SDKs and strongly-typed consumers will see type names and shapes change.

  • SDK error-type renames: identical inline error schemas used to produce one Go, TypeScript, or Python type per operation, with names derived from the alphabetically-first operation that referenced them. They now collapse into one semantic type per error shape. Typical renames you'll see after regeneration:

    Before (example) After
    ListProfiles400Response PaginationError
    UpdateProfile400Response BadRequest
    GetProfile404Response NotFound
    IgnoreScan409Response Conflict
    CreateAssetComment500Response InternalServerError

    Update imports and type references to the new names. Payload fields are unchanged.

  • GET /scans/{scanId}/targets 400 schema narrowed: the declared 400 used to be a union of BadRequest and PaginationError. The server has only ever returned the pagination variant on this endpoint, so the spec now declares a single PaginationError. Regenerated SDKs drop the union wrapper. Hand-written error handlers only need to match on "Invalid cursor" for this endpoint. Runtime responses don't change.

Non-breaking changes

  • Named schemas in the OpenAPI spec: every 400, 404, 409, and 500 response now carries an explicit title and description for BadRequest, PaginationError, NotFound, Conflict, and InternalServerError. Payload shapes for reference:

    HTTP Schema Shape
    400 BadRequest { "message": "Bad Request", "details": string }
    400 PaginationError { "message": "Invalid cursor", "details": string }
    404 NotFound { "message": "Not found" }
    409 Conflict { "message": "Conflict on the following field", "field": string, "instanceId": uuid }
    500 InternalServerError { "message": "Internal Server Error", "details": string }
  • No changes to operations, paths, methods, parameters, request bodies, success responses, or authentication.

What's Next

We keep improving the Public API, and there's more on the way.

Learn More

Questions?

Have a question? Reach out on your dedicated support channel (Slack, Microsoft Teams, or whichever channel we've set up with your team), or email us at support@escape.tech.

#160 · LLM Security Testing in DAST: Find AI Vulnerabilities in the Scan You Already Run

Availability: Beta General Availability planned for end of April 2026.

Modern apps ship chatbots, AI agents, RAG endpoints, and copilot features faster than security teams can audit them. Each one is a new attack surface: prompt injection, system prompt leakage, tool exposure, SSRF through model-driven HTTP calls. A traditional DAST scan can't see any of it. LLM Security Testing closes that gap, with automatic discovery and deterministic OWASP LLM Top 10 checks that run inside your existing WebApp, REST API, and GraphQL DAST scans.

What's New

  • Automatic LLM endpoint discovery: Escape fingerprints LLM traffic from network signals (SSE streaming, OpenAI / Anthropic / Gemini response shapes, token-usage fields), JavaScript source (openai, @anthropic-ai/sdk, langchain, Vercel AI SDK), and GraphQL operation patterns. No allow-listing, no manual configuration.
  • Six active OWASP LLM Top 10 checks: prompt injection (LLM01), insecure output handling (LLM02), system prompt leakage (LLM01 + LLM06), LLM command injection (LLM07), LLM-enabled SSRF (LLM07), and tool / function-calling exposure (LLM08).
  • Always-on AI inventory: an ISSUE_LLM_DETECTED finding maps every AI endpoint we see, with model, provider, framework, auth posture, and tool exposure. You know where AI lives in your stack before any active probe runs.
  • Deterministic verification, not an LLM judge: every finding is confirmed by a canary substring, an out-of-band callback, a cloud-metadata marker, or a JSON-schema match. Reproducible, auditable results with no model-driven false positives.
  • Runs in the scan you already have: zero new scan profile, zero new infrastructure. Reuses your authenticated session (cookies, bearer tokens, CSRF nonces, persisted GraphQL queries).

Why It Matters

"We've got a lot of AI stuff going on, chatbots, AI agents, will that be tested?" is how AppSec leads have been describing their world on our calls. Until now, the honest answer inside a DAST scan was no: prompt injection, system-prompt leakage, and tool exposure don't fall out of standard test catalogues, and AI-judge verification swaps one triage headache for another (non-deterministic AI-vs-AI verdicts). LLM Security Testing gives you a deterministic floor: high-confidence OWASP LLM Top 10 detections, one finding per confirmed issue, with the raw HTTP request and response shipped as audit evidence.

How to Get Started

LLM Security Testing is opt-in during the Beta. Reach out through your support channel, the contact form, or support@escape.tech and we'll help you enable it on your scan profile. The knob lives under experimental.llm_security_testing:

experimental:
  llm_security_testing: true

On your next scan, every confirmed OWASP LLM Top 10 issue lands in your results with full evidence: prompt sent, response excerpt, matched canary or out-of-band callback, remediation guidance. LLM-enabled SSRF and command injection are confirmed through ssrf.tools.escape.tech, the same out-of-band collector that powers Escape's existing SSRF checks, with per-scan and per-probe identifiers so callbacks are never ambiguous.

By design, no synthetic traffic. Endpoints discovered only via static JavaScript analysis (never exercised by the crawler or recorded in a BLST exchange) get the inventory finding, but the six active checks don't run against them. You only ever see probes against endpoints your application actually serves.

With the knob off, the module adds zero overhead to your normal scan time. Existing DAST scans are unaffected until you opt in.

Compatibility

Non-breaking changes

  • New issue types in scan results: ISSUE_LLM_DETECTED, prompt injection (LLM01), insecure output handling (LLM02), system prompt leakage (LLM01 + LLM06), LLM command injection (LLM07), LLM-enabled SSRF (LLM07), and tool / function-calling exposure (LLM08). Existing schemas and fields are unchanged; integrations with open-enum issue-type matching pick them up automatically.

What's Next

The deterministic module catches what's broken. The other half of AI security is adversarial depth: multi-turn jailbreaks, escalating from a leaked tool schema into a real RCE, pivoting through agent memory, and proving full business-impact exploitation on the most stubborn targets. That's coming to AI Pentesting as the LLM Security Testing Agent, an autonomous, goal-driven adversary that picks up where the deterministic checks leave off, generates new payloads on the fly, and targets RAG pipelines, function-calling chains, MCP servers, and multi-agent orchestrations end-to-end. Want early access? Talk to our team.

Learn More

Questions?

Have a question? Reach out on your dedicated support channel (Slack, Microsoft Teams, or whichever channel we've set up with your team), or email us at support@escape.tech.

#159 · 04-15-2026 — Public API Release Notes

This release expands the v3 Public API with new endpoints for reporting, issue operations, asset workflows, tags, and ASM automation. It also enriches several existing response schemas with additional metadata to support deeper integrations and better visibility.

Hard-breaking changes

None.

Soft-breaking changes

These changes are additive and backward-compatible for most clients, but may affect consumers using strict schema validation.

  • Asset responses now include owners email addresses.
  • Profile summary responses now include:
    • score
    • coverage
    • openIssueCount
    • lastScanStatus
  • Location summary responses now include:
    • lastSeenAt

Non-breaking changes

New endpoints

  • GET /v3/statistics

    • Returns high-level organization statistics for applications, monitored assets, and issues by severity.
  • GET /v3/issues/funnel

    • Returns issue funnel data to help track issue progression and exposure.
  • GET /v3/issues/trends

    • Returns time-series issue severity trends.
  • POST /v3/issues/bulk-update

    • Bulk update issue status across multiple matching issues.
  • POST /v3/issues/{issueId}/notify

    • Notify asset owners about a specific issue.
  • POST /v3/assets/bulk-update

    • Bulk update assets.
  • POST /v3/assets/bulk-delete

    • Bulk schedule assets for deletion.
  • GET /v3/tags/{tagId}

    • Retrieve a tag by ID.
  • PUT /v3/tags/{tagId}

    • Update a tag.
  • GET /v3/assets/{assetId}/activities

    • List activities for an asset.
  • POST /v3/assets/{assetId}/activities

    • Add a comment/activity to an asset.
  • POST /v3/asm/scans

    • Trigger ASM scans programmatically.

Existing endpoint improvements

  • GET /v3/scans

    • Added support for filtering by assetIds.
  • GET /v3/custom-rules

    • Added support for filtering by context.

Summary

This release is focused on expanding the v3 Public API without introducing hard-breaking changes. It adds new operational and reporting endpoints, improves filtering capabilities, and enriches existing resource payloads with more useful metadata for customer integrations.

#158 · Workflows API OpenAPI v3.1

Breaking changes

Workflows API restructured

The single-workflow endpoints have been replaced with a resource-oriented API. You will need to update any integration that calls the workflows endpoints.

┌───────────────────┬────────────────────────┐ │ Old │ New │ ├───────────────────┼────────────────────────┤ │ GET /workflows │ GET /workflows/{id} │ ├───────────────────┼────────────────────────┤ │ PUT /workflows │ PUT /workflows/{id} │ ├───────────────────┼────────────────────────┤ │ DELETE /workflows │ DELETE /workflows/{id} │ └───────────────────┴────────────────────────┘

A new GET /workflows endpoint now returns a paginated list of all your workflows (instead of a single workflow object).


Non-breaking changes

  • OpenAPI spec upgraded to 3.1 — the spec served at /v3/openapi.json now uses the OpenAPI 3.1 format. Nullable fields are now expressed as type: ["X", "null"] instead of nullable: true. This is semantically equivalent; most client generators handle both.
  • New POST /workflows endpoint added to create workflows programmatically.
  • Automated Pentest GraphQL profile (POST /profiles/ai-pentesting/graphql) — internal stability metadata removed from the spec; no functional change.

#157 · Better asset filtering & bug fixes

We've made significant improvements to how asset sources are handled across the Attack Surface Management module, with better filtering, bug fixes, and a more consistent experience throughout.

What's new

You can now filter assets in tables by their source type — currently Manually created and Integration are supported, with filtering by specific asset source coming soon.

Screenshot 2026-02-20 at 09.37.15.png

Behind the scenes, we've centralized and reworked the sources logic, ensuring that source information is coherent and consistent across all views. This also came with a large number of bug fixes that were causing sources to display incorrectly in certain contexts.

Bug fixes & improvements

Fixed multiple inconsistencies in how sources were displayed across different views Centralized source logic to ensure reliability and consistency going forward Added table filtering by source type (Manual / Integration)

#156 · Private Asset Detection Now Available in Escape ASM

We've expanded our risk detection capabilities to identify private assets across your attack surface — assets whose addresses are not resolvable on the public internet.

Screenshot 2026-02-20 at 09.17.18.png

What's new

When scanning your assets, we now automatically flag any asset whose IP address or domain name resolves to a private or non-routable address. These assets will appear in your ASM dashboard, so your team can review and act on them.

What counts as a private asset

An asset is considered private if its address falls into any of the following categories:

  • Local domains — any .local domain, including Kubernetes services (.svc.cluster.local)
  • Private IP ranges — 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16, as well as their IPv6 equivalents
  • Loopback addresses — localhost, 127.0.0.0/8, and ::1
  • CGNAT range — 100.64.0.0/10

Why it matters

Private assets appearing in your external attack surface can indicate misconfigured services, unintended internal exposure, or infrastructure leaking details about your internal network topology. Identifying them early helps your team prioritize remediation and reduce the risk of internal systems being inadvertently reachable or discoverable.

What to do

Review any private assets flagged in your ASM (Attack Surface Management) dashboard and assess whether their presence is expected. If not, investigate the underlying service configuration and ensure internal resources are not inadvertently exposed.

#155 · Multi-Schema Support for Scan Profiles

APIs built on microservices often have one schema per service. Scanning them together meant merging files manually or accepting gaps in your security coverage.

Now you can attach multiple schemas to a single scan profile. Your full API surface gets tested, without the prep work.

What's new

  • Manage schemas from two places. Use the profile's Schemas section in Settings, or the service's side panel in the ASM.
  • Attach schemas during profile creation. Pick from existing assets, or create new ones on the fly via upload, fetch, or directly from the ASM.
  • Scan APIs using multiple schemas. All attached schemas are used during the scan.

How to use it in the UI:

  • During profile creation:
    • Go to the "Create a new scan profile" step and select your API type.

image.png

  • If a schema doesn't appear in the list, it may not be linked to the target asset yet.

image.png

  • Create it on the fly:

image.png

  • or link it first from the ASM:

image.png

If schema(s) are available, toggle on the schemas you want to include. Check "Use all available extra assets" to always include every linked schema automatically.

image.png

  • For existing profiles: Go to Settings → Schemas. Add, remove, or unlink schemas anytime. Unlinking removes the schema from all profiles scanning that target.

image.png

Unlinking extra schemas from a target asset will require a confirmation and it will remove the asset from the extra assets of all the profiles scanning the target asset.

image.png

The more schemas your scan profile includes, the closer your security coverage gets to your real attack surface.

For extra setup guidance and troubleshooting, learn more in the docs.