The security invariant

Validate the destination of the connection you are about to make.

01 / The boundary

A safe first destination says nothing about the next one.

A server-side HTTP request spends the application’s network access on behalf of someone else. That makes the destination a security decision. In Twenty, the affected secure HTTP client checked an initial URL before handing the request to Axios. The upstream advisory records a gap when that request followed a redirect: the next destination did not receive the same validation.

The useful review question is about the lifetime of that decision. A URL check can be correct for the input it sees and still be insufficient for the operation it authorizes. When a response supplies a new destination, the application is about to make another network request. The earlier approval needs a defined scope; it cannot establish trust in a server chosen later.

02 / Request path

The security check ended before redirect handling did.

The pre-fix adapter assembled the URL, rejected unsupported protocols, resolved the hostname and rejected a private address. It then created a custom lookup function that returned the validated address. This protected the initial lookup from being replaced by a different DNS answer. Finally, it delegated execution to the standard HTTP adapter.

The source also selected only one custom agent, according to the starting protocol. An HTTPS request therefore configured the HTTPS agent alone. A later redirect to HTTP could use a different transport path. The advisory describes both missing redirect validation and this cross-protocol gap. These are related coverage failures: the component that approves the first request does not control every subsequent connection.

Where the destination decision lives
Before the fix
  1. Check the initial URL

    Resolve and approve the first destination.

  2. Follow a redirect

    A response supplies a different destination.

  3. Open the next connection

    The initial check is not repeated.

After the fix
  1. Receive a destination

    Initial URL or redirect target.

  2. Validate the connection

    HTTP and HTTPS agents enforce the policy.

  3. Allow or stop

    A private destination fails validation.

Conceptual control flow reconstructed from the upstream source. It is not a captured request or a TraceMint execution trace.

03 / Source & fix

Move enforcement to the connection boundary.

The upstream patch replaces the adapter with dedicated agents. Each agent checks a literal host address in createConnection and attaches a handler for the socket’s DNS lookup event. A private resolved address causes the socket to be destroyed; an address that cannot be validated also closes the socket. Both HTTP and HTTPS receive this behavior.

The service installs both agents when outbound safe mode is enabled. The checked revision also sets a maximum of five redirects, while respecting a lower caller-supplied limit. That bound limits the length of a chain. The security boundary comes from destination validation on the connection path: one redirect can still cross a boundary even when a redirect budget is small.

This is a change in where the invariant is enforced. Callers no longer need to predict which transport a redirect will use. The agent that creates the new connection applies the destination policy at the point where that connection becomes concrete.

Before · initial DNS resultSource
const { address: resolvedIp, family } = await dnsLookup(url.hostname);
get-secure-axios-adapter.util.tse4aad775
After · both transportsSource
httpAgent: createSsrfSafeAgent('http'),httpsAgent: createSsrfSafeAgent('https'),
secure-http-client.service.ts610c0ebc
After · connection enforcementSource
validateHost(options.host ?? undefined);return attachLookupValidation(super.createConnection(options, callback));
create-ssrf-safe-agent.util.ts610c0ebc

Selected upstream lines; indentation normalized. Links include surrounding code at immutable revisions.

04 / Impact & conditions

Network reachability determines the practical exposure.

Twenty rates the issue Moderate, with a CVSS 3.1 score of 5.0. The advisory describes access to internal service responses and identifies versions through 1.17 as affected, with 1.18 patched. Its scope is conditional: the attacker must be able to influence an outbound URL, and the application server must be able to reach the destination.

An authenticated actor
The published attack requires a logged-in user with control over an outbound request URL.
A redirected request
A controllable initial endpoint supplies the next destination.
A reachable internal service
Network placement and the target service’s own protections affect what can be exposed.
05 / Review & regression

Test the transition, as well as the destination.

The patch includes unit tests for agent creation, literal private addresses, DNS lookup outcomes and redirect limits. Those tests document the intended controls. Reading a test is evidence of coverage in source; it does not establish that a particular deployed environment passed an integration test.

A regression review should also exercise the boundary through an actual HTTP client in an isolated fixture. Use endpoints owned by the test and a controlled destination classified as private. Observe connection attempts as well as the final response: a request that returns an error may still have contacted a forbidden service. The scenarios below are suggested review checks, not reported TraceMint test results.

Suggested regression checks
ScenarioExpected boundary
Allowed URL → allowed URLLegitimate redirect behavior continues within the configured limit.
Allowed URL → private destinationThe redirected connection fails destination validation.
HTTPS → HTTP redirectThe destination policy remains active after the protocol change.
Hostname → private DNS answerThe resolved address is rejected on the connection path.
06 / Lessons & limits

Match a check’s scope to the operation it protects.

For reviewers, the high-value seam is the handoff between an application wrapper and a library that performs more work internally. Redirects, retries and transport changes deserve explicit questions: which inputs can change, which component creates the next connection, and which security policy still applies? A check is useful only for the set of operations it actually governs.

For maintainers, preserve a benign success case beside each rejected case. A fix that prevents all requests would satisfy a narrow negative test while breaking the product. Review safe-mode configuration and the caller’s use of the protected client alongside the patch; the implementation shown here is not a claim that every outbound path in every deployment is covered.

The public advisory credits the TraceMint account as Finder. The patch is upstream remediation. This study analyzes the public record and immutable source revisions; it does not establish a private discovery sequence, a product execution method, or observed compromise of a customer environment.

Source record

Follow the evidence.

Public upstream records and immutable code revisions, reviewed 2026-09-19.

  1. Twenty security advisory

    Impact, prerequisites, versions, severity and finder credit.

  2. Adapter before the fix

    Immutable parent revision · e4aad775 · URL validation, DNS pinning and adapter handoff.

  3. Upstream corrective commit

    610c0ebc · the complete change and its parent revision.

  4. Connection-level agents

    Literal-host checks and validation of socket lookup results.

  5. Client configuration after the fix

    Both agents in safe mode; five-redirect cap in the committed source.

  6. Upstream agent tests

    Unit cases for address validation and HTTP/HTTPS agent behavior.

  7. Upstream client tests

    Safe-mode configuration and redirect-budget expectations.

Brief code excerpts from twentyhq/twenty. Upstream license: GNU AGPL v3. All remediation described here is upstream work.

Read the original record

This case study analyzes an already-public advisory and upstream source. For the complete impact, remediation and credit record, see the Twenty security advisory.

Editorial publication is separate from disclosure. No private discovery timeline or method has been inferred.

More credited contributions