Skip to content

Normalize raw remote IP addresses with ports#307

Open
Mishenevd wants to merge 1 commit into
mainfrom
fix/runtime-user-ip-port-normalization
Open

Normalize raw remote IP addresses with ports#307
Mishenevd wants to merge 1 commit into
mainfrom
fix/runtime-user-ip-port-normalization

Conversation

@Mishenevd

@Mishenevd Mishenevd commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Normalize raw remote IP addresses before storing runtime user IPs.

In some servlet container configurations, the Java agent can receive a remote address in ip:port format through the raw request remote address path, not through the X-Forwarded-For parser.

This can happen with Spring Boot/Tomcat native forwarded-header handling: Tomcat consumes the X-Forwarded-For header and exposes its value through request.getRemoteAddr().

Before this change, the fallback path returned rawIp unchanged. As a result, SetUser could store and report runtime user IPs like:

109.132.232.101:58780

This caused the same client IP to be reported as multiple different runtime user IPs when the source port changed.

Changes

  • Added normalization for fallback raw remote addresses.

  • Reused the same normalization for forwarded-header candidates.

  • Handles:

    • plain IPv4 / IPv6
    • IPv4 with port, e.g. 109.132.232.101:58780
    • bracketed IPv6, e.g. [2001:db8::1]
    • bracketed IPv6 with port, e.g. [2001:db8::1]:443
  • Preserves the previous fallback behavior for values that cannot be parsed.

Testing

Targeted tests:

./gradlew :agent_api:test --tests helpers.ProxyForwardedParserTest
./gradlew :agent_api:test --tests context.JavalinContextObjectTest
./gradlew :agent_api:test --tests SetUserTest

Covered cases:

  • raw remote IPv4 address with source port
  • bracketed IPv6 with port
  • bracketed IPv6 without port
  • X-Forwarded-For with bracketed IPv6 port
  • trust-proxy-disabled fallback behavior
  • SetUser using the normalized IP from request context

Local E2E smoke:

  • Ran a Spring Boot/Tomcat test app with --server.forward-headers-strategy=native
  • Set AIKIDO_TRUST_PROXY=false
  • Sent X-Forwarded-For: 109.132.232.101:58780
  • Verified Tomcat consumes the header and exposes it as raw remote address:
{
  "remoteAddr": "109.132.232.101:58780",
  "xForwardedFor": null
}
  • Redirected the Java agent to a local mock Aikido backend and captured heartbeat payloads.

Old agent behavior:

"users": [
  {
    "id": "admin@tenant-a.test",
    "name": "Admin",
    "lastIpAddress": "109.132.232.101:58780"
  }
]

Fixed agent behavior:

"users": [
  {
    "id": "admin@tenant-a.test",
    "name": "Admin",
    "lastIpAddress": "109.132.232.101"
  }
]

Summary by Aikido

Security Issues: 0 🔍 Quality Issues: 1 Resolved Issues: 0

⚡ Enhancements

  • Normalized raw remote IP addresses and ports before storing

More info

@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.30769% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...do/agent_api/helpers/net/ProxyForwardedParser.java 92.30% 0 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

@Mishenevd Mishenevd force-pushed the fix/runtime-user-ip-port-normalization branch from 38f26de to 893558b Compare June 24, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants