Skip to content

fix: validate objectType and encode path params in managed-object tools (IAM-11741) - #72

Merged
daveernstingFR merged 1 commit into
mainfrom
polaris/IAM-11741-fix-objecttype-path-traversal
Oct 19, 2026
Merged

daveernstingFR merged 1 commit into
mainfrom
polaris/IAM-11741-fix-objecttype-path-traversal

Conversation

@daveernstingFR

@daveernstingFR daveernstingFR commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Closes a path-traversal vulnerability in the managed-object tools (IAM-11741). The objectType argument was validated only as a non-empty string and interpolated raw into privileged outbound IDM URLs. Node's WHATWG URL parser normalizes ../ dot segments before sending and treats ?/# as URL delimiters, so a caller holding only identity scopes could retarget the server's privileged fr:idm:* admin token at any IDM endpoint — including /openidm/config/* (tenant-wide configuration: SMTP credentials, script hooks, connector configs). Verified locally: raw interpolation of alpha_user/../../config/sync resolves to /openidm/config/sync.

The fix applies two defense layers:

  1. Boundary — a shared zod schema managedObjectTypeSchema (^[a-zA-Z0-9_]+$) in src/utils/managedObjectHelpers.ts, adopted by all six affected tools. Regex verified against official Ping documentation: the AIC admin console restricts object type keys to a-z A-Z 0-9; the legacy native console adds _; the repo's definition tools already enforce the identical regex; internal/role is a separate endpoint, not a managed object type.
  2. Sink — encodeURIComponent on objectType at all five URL construction sites and on objectId at the three two-param sites. new URL(...) alone does not protect (template interpolation happens before WHATWG normalization), so the encoding is what neutralizes traversal.

Tools covered: createManagedObject, getManagedObject, deleteManagedObject, patchManagedObject, queryManagedObjects (the five from the ticket) plus getManagedObjectSchema (same weak schema, constant URL, added for consistency). patchManagedObjectRelationship already used safePathSegmentSchema and is untouched. No changes to shared helpers (apiHelpers.ts, validationHelpers.ts untouched).

🤖 Generated with Claude Code

Test plan

  • All six tools reject traversal/delimiter payloads (../config/, alpha_user/../../config/sync, %2e%2e, a?b, a#b, '') at the MCP validation layer — Verified by Polaris QA (drove the real McpServer over InMemoryTransport: every payload returns -32602 input validation, toolFunction never executes)
  • Sink encoding neutralizes a payload that bypasses the zod boundary — Verified by Polaris QA (direct toolFunction calls on the built dist resolve every payload to a path under /openidm/managed/, e.g. ..%2Fconfig%2Fsync; regression test added and mutation-verified)
  • No behavioral change for legitimate inputs — Verified by Polaris QA (existing request-construction tests with alpha_user, obj-123, alpha_device pass unmodified; full suite 1264 tests green)
  • Snapshot schemas updated for the six tools (_def.checks: min → regex) — Verified by Polaris QA
  • Scope: exactly 19 files changed; apiHelpers.ts, validationHelpers.ts, patchManagedObjectRelationship.ts untouched — Verified by Polaris QA
  • npm run lint, npm run format:check, npm run typecheck, npm test, npm run build all pass — Verified by Polaris QA

Fixes IAM-11741.

…ls (IAM-11741)

Managed-object tools interpolated the `objectType` argument into outbound
IDM URLs with only a non-empty-string check. Because the WHATWG URL parser
normalizes `../` segments and treats `?`/`#` as delimiters before a request
is sent, a crafted value could redirect these privileged `fr:idm:*` calls
to arbitrary IDM endpoints (e.g. `/openidm/config/*`).

Two-layer fix:

- Boundary: shared `managedObjectTypeSchema` allowlist (`^[a-zA-Z0-9_]+$`,
  the character set documented for managed object type keys) applied to
  `objectType` in create/get/delete/patch/query/getManagedObjectSchema.
- Sink: `encodeURIComponent` on `objectType` at all five URL construction
  sites and on `objectId` at the three two-param sites, so encoding holds
  even for inputs that reach a tool without MCP-level validation.

Also regenerates the six affected tool-schema snapshots and hardens the
objectType tests to assert traversal/delimiter payloads are rejected, plus
a regression test asserting the request path stays under /openidm/managed/
for an encoded traversal payload.

Gates: lint, format:check, typecheck, build, and the full vitest suite
(1264 tests) all pass.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@daveernstingFR
daveernstingFR force-pushed the polaris/IAM-11741-fix-objecttype-path-traversal branch from 0eb711f to da4b38e Compare October 19, 2026 09:45
@daveernstingFR
daveernstingFR merged commit 0fc1465 into main Oct 19, 2026
4 checks passed
@daveernstingFR
daveernstingFR deleted the polaris/IAM-11741-fix-objecttype-path-traversal branch October 19, 2026 09:46
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