Skip to content

feat(auth): org IP allowlisting — member network restrictions#5872

Open
waleedlatif1 wants to merge 8 commits into
stagingfrom
feat/org-ip-allowlist
Open

feat(auth): org IP allowlisting — member network restrictions#5872
waleedlatif1 wants to merge 8 commits into
stagingfrom
feat/org-ip-allowlist

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • New enterprise org setting: IP access (org plane, security group) — an enable toggle + allowlist of IPv4/IPv6 addresses or CIDR ranges (optional # label per entry, up to 200). When enabled, org members can only sign in and use Sim from allowed addresses.
  • Enforced at the getSession chokepoint so every session-authenticated route and layout re-checks the policy (not just hybrid-auth routes) — a denied member resolves as signed out. Also enforced at session establishment (sign-in hook), the API-key auth path (checkHybridAuth), and the realtime Socket.IO handshake.
  • Exempt (intentional, documented): deployed chats, public form shares, webhooks, scheduled executions — outward-facing product surfaces that authenticate by their own means; internal-JWT/webhook-signature paths never hit the check.
  • Save-time lockout guard: enabling a list that excludes the caller's own trusted IP is rejected; enabling with an empty list is rejected (contract superRefine). The settings page shows the caller's current IP.
  • Fail-closed: when a policy is active but no trustworthy client IP can be derived (multi-hop proxy chain without AUTH_TRUSTED_PROXIES), access is denied. DISABLE_ORG_IP_ALLOWLIST is the break-glass (read at call time, no restart needed).
  • Denial audit events (organization.ip_access.denied, throttled per-member) plus the policy-change event, so security teams see who's blocked and from where.
  • Trusted-proxy IP resolution reuses better-auth's hardened resolver (from PR improvement(auth): bump better-auth to 1.6.23 and add trusted-proxy client IP resolution #5857) with AUTH_TRUSTED_PROXIES; shared parseTrustedProxies/buildIpResolutionOptions helpers replace three duplicated parse blocks.
  • Migration 0267: additive organization.network_policy_settings json column. Reuses securityPolicyVersion (from feat(auth): org session policies — lifetime/idle limits, org-wide revocation #5862) so policy changes invalidate cached session cookies org-wide within ~60s.
  • Pure, dependency-free IP/CIDR matcher in @sim/platform-authz/network (43 tests), shared by the app, the realtime server, and the contract validator (client-bundle-safe — no node:net).

Industry validation

Design cross-checked against 12 platforms' live admin docs (GitHub Enterprise, Datadog, Atlassian, Salesforce, Okta, Google Workspace, Notion, Figma, Slack, Workato, Zapier, Retool). Our core (enterprise-gated, IPv4/IPv6/CIDR, continuous enforcement incl. API keys, product-outward exemptions, hard save-time lockout guard, fail-closed + break-glass) matches or exceeds the mature implementations; Zapier and Retool Cloud don't offer this natively at all. The two gaps every mature impl has — per-entry labels and denial audit events — are both implemented here.

Type of Change

  • New feature

Testing

  • 43 matcher tests (IPv4/IPv6/CIDR/labels/malformed/IPv4-mapped/family-scoping), 8 route tests (authz, malformed CIDR, lockout guard, unresolvable-IP fail-closed, disable-skips-guard), audit-mock sync
  • 738 app tests + platform-authz + audit suites green; typecheck, lint, check:api-validation, check:migrations, check:utils all pass
  • /simplify (research + 4 angles) and /cleanup (8 passes) applied — see commits
  • Not yet live-tested — staging verification: enable a policy from an allowed IP → off-network member blocked within ~60s; realtime connect blocked; lockout guard rejects self-exclusion; break-glass env restores access

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@waleedlatif1
waleedlatif1 requested a review from a team as a code owner July 23, 2026 00:19
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 23, 2026 1:20am

Request Review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor

cursor Bot commented Jul 23, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Touches authentication, session resolution, and API access across app and realtime; misconfigured proxies or policy bugs could lock out entire orgs despite lockout guards and break-glass env.

Overview
This PR adds Enterprise IP access controls: org admins configure an IPv4/IPv6/CIDR allowlist (stored in new organization.network_policy_settings) and a Restrict access by IP toggle via Settings → IP access and GET/PUT /api/organizations/[id]/network-policy, with save-time lockout prevention and securityPolicyVersion bumps so policy changes propagate within ~60s.

Enforcement is wired through enforceOrgNetworkPolicy / trusted-proxy IP resolution (AUTH_TRUSTED_PROXIES, fail-closed when IP is unknown): customSession and sign-in block session use from disallowed IPs; hybrid and v1 API-key auth; socket-token minting via getSession; and realtime Socket.IO handshakes (separate middleware with throttled denial audits). Deployed chats, webhooks, and similar outward surfaces stay exempt. Break-glass: DISABLE_ORG_IP_ALLOWLIST.

Also adds enterprise docs, navigation/registry entries, env flags for self-hosted, migration 0266, and audit actions for policy updates and denied access.

Reviewed by Cursor Bugbot for commit a073439. Configure here.

Comment thread apps/sim/lib/auth/network-policy.ts Outdated
@greptile-apps

greptile-apps Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds organization IP allowlisting across member authentication paths. The main changes are:

  • IPv4, IPv6, CIDR, label, and mapped-address parsing in the shared authorization package.
  • Enforcement for sign-in, existing sessions, API keys, socket tokens, and realtime connections.
  • Trusted-proxy resolution, fail-closed handling, break-glass configuration, and denial auditing.
  • Enterprise settings APIs, lockout prevention, persistence, cache invalidation, and policy versioning.
  • Organization settings UI, documentation, migration data, and test coverage.

Confidence Score: 5/5

This looks safe to merge.

  • The realtime path now denies unresolved forwarded-address chains without falling back to the proxy peer.
  • Realtime denial branches now record throttled audit events.
  • Numeric mapped-address handling covers compressed, expanded, and hexadecimal forms consistently.
  • No blocking issue remains in the reviewed fixes.

Important Files Changed

Filename Overview
apps/realtime/src/middleware/network-policy.ts Adds realtime policy loading, trusted client-IP resolution, allowlist enforcement, and throttled denial auditing.
apps/realtime/src/middleware/auth.ts Applies the organization network policy before establishing an authenticated socket.
packages/platform-authz/src/network.ts Adds dependency-free IP and CIDR parsing with numeric canonicalization for mapped IPv6 addresses.
packages/platform-authz/src/network.test.ts Covers IPv4, IPv6, CIDR, labels, malformed entries, mapped addresses, and family boundaries.
apps/sim/lib/auth/network-policy.ts Centralizes app-side policy loading, trusted-IP resolution, enforcement, caching, and denial auditing.
apps/sim/app/api/organizations/[id]/network-policy/route.ts Adds authorized policy reads and updates with enterprise gating and lockout prevention.

Reviews (9): Last reviewed commit: "fix(realtime): bound socket denial-audit..." | Re-trigger Greptile

@greptile-apps

greptile-apps Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds organization-level IP access restrictions across authenticated product surfaces. The main changes are:

  • IPv4, IPv6, CIDR, and labeled-entry validation and matching.
  • Enforcement for sessions, API keys, and realtime connections.
  • Enterprise settings UI, API contracts, persistence, and cache invalidation.
  • Policy-change and access-denial audit events.
  • Administrator documentation and tests.

Confidence Score: 4/5

The realtime enforcement path and mapped-address matching need fixes before merging.

  • An unresolved forwarded chain can be replaced with the proxy peer address and incorrectly pass the allowlist.
  • Accepted mapped IPv6 CIDRs do not match mapped client addresses.
  • Realtime-only denials are missing from the security audit log.

apps/realtime/src/middleware/network-policy.ts; packages/platform-authz/src/network.ts

Security Review

Realtime IP resolution can fall back from an unresolved forwarded chain to the reverse proxy address, allowing clients when that proxy is covered by the allowlist. Realtime-only denials also bypass the new security audit event.

Important Files Changed

Filename Overview
apps/realtime/src/middleware/network-policy.ts Adds realtime policy enforcement, but unresolved proxy chains can fall back to an allowed proxy address and denials are not audited.
packages/platform-authz/src/network.ts Adds shared IP and CIDR matching, with an inconsistency between accepted mapped IPv6 CIDRs and mapped client-address matching.
apps/sim/lib/auth/network-policy.ts Adds cached app-side policy resolution, trusted-IP checks, entitlement gating, and throttled denial auditing.
apps/sim/app/api/organizations/[id]/network-policy/route.ts Adds member reads and enterprise-admin updates with lockout prevention and policy-version invalidation.
apps/sim/lib/auth/auth.ts Adds policy enforcement during session creation and at the central session-read path.
apps/sim/lib/auth/hybrid.ts Adds network-policy enforcement to successful API-key authentication.
apps/sim/ee/network-policy/components/network-policy-settings.tsx Adds the enterprise allowlist editor with validation and save or discard behavior.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Authenticated request] --> B{Authentication path}
  B -->|Session or API key| C[App policy enforcement]
  B -->|Socket handshake| D[Realtime policy enforcement]
  C --> E[Load member organization policy]
  D --> E
  E --> F[Resolve trusted client IP]
  F --> G{Address matches allowlist?}
  G -->|Yes| H[Allow access]
  G -->|No or unresolved| I[Deny and record audit event]
  F -. unresolved socket chain .-> J[Fallback to proxy peer]
  J -. proxy may be allowed .-> H
Loading

Reviews (1): Last reviewed commit: "polish(network-policy): fix orphaned TSD..." | Re-trigger Greptile

Comment thread apps/realtime/src/middleware/network-policy.ts Outdated
Comment thread packages/platform-authz/src/network.ts Outdated
Comment thread apps/realtime/src/middleware/network-policy.ts
…pped-CIDR matching, realtime fail-open+audit consistency, drop dead exports
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

Additional fix in this round from an internal enforcement-coverage audit (not flagged by review, but a real bypass): the public /api/v1/** REST surface authenticated the same personal/workspace API keys via authenticateV1Request but never called enforceOrgNetworkPolicy — a member under an IP restriction could bypass the allowlist entirely by using v1 instead of the legacy path. Now enforced there too, mirroring checkHybridAuth. Also dropped two internal-only exports and bounded the denial-audit throttle map.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/realtime/src/middleware/network-policy.ts Outdated
Comment thread apps/sim/lib/auth/auth.ts Outdated
…(covers client session), match realtime break-glass to isTruthy
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/realtime/src/middleware/network-policy.ts
Comment thread apps/realtime/src/middleware/network-policy.ts
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 2ca9a67. Configure here.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

Comment thread packages/platform-authz/src/network.ts Outdated
…extual forms (compressed/expanded/hex) match uniformly
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/realtime/src/middleware/network-policy.ts
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/lib/auth/network-policy.ts
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit a073439. Configure here.

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.

1 participant