{"record":{"id":"b0bf4af8f09ac3a4","repo":"pinpoint-apm/pinpoint","slug":"webhook-url-user-info-is-not-allowed","errorCode":null,"errorMessage":"Webhook URL user info is not allowed","messagePattern":"Webhook URL user info is not allowed","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"commons-server/src/main/java/com/navercorp/pinpoint/common/server/webhook/WebhookUrlValidator.java","lineNumber":126,"sourceCode":"        if (scheme == null) {\n            throw new IllegalArgumentException(\"Webhook URL scheme is required\");\n        }\n\n        String normalizedScheme = scheme.toLowerCase(Locale.ROOT);\n        if (!\"http\".equals(normalizedScheme) && !\"https\".equals(normalizedScheme)) {\n            throw new IllegalArgumentException(\"Webhook URL scheme must be http or https\");\n        }\n    }\n\n    private static void validateAuthority(URI uri) {\n        if (uri.getHost() == null || uri.getHost().isBlank()) {\n            throw new IllegalArgumentException(\"Webhook URL host is required\");\n        }\n        if (isBlockedHostLiteral(uri.getHost())) {\n            throw new IllegalArgumentException(\"Webhook URL host is not allowed\");\n        }\n        if (uri.getRawUserInfo() != null) {\n            throw new IllegalArgumentException(\"Webhook URL user info is not allowed\");\n        }\n        if (uri.getRawFragment() != null) {\n            throw new IllegalArgumentException(\"Webhook URL fragment is not allowed\");\n        }\n        int port = uri.getPort();\n        if (port == -1 && hasExplicitPort(uri)) {\n            throw new IllegalArgumentException(\"Webhook URL port is not valid\");\n        }\n        if (port == 0 || port > MAX_PORT) {\n            throw new IllegalArgumentException(\"Webhook URL port is not allowed\");\n        }\n    }\n\n    private static boolean hasExplicitPort(URI uri) {\n        String rawAuthority = uri.getRawAuthority();\n        if (rawAuthority == null || rawAuthority.isEmpty()) {\n            return false;\n        }","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/commons-server/src/main/java/com/navercorp/pinpoint/common/server/webhook/WebhookUrlValidator.java#L108-L144","documentation":"WebhookUrlValidator.validateAuthority throws IllegalArgumentException when the URL contains user info (rawUserInfo != null), i.e. credentials embedded as scheme://user:pass@host. Embedding credentials in webhook URLs is disallowed for security (leaks secrets in logs/refs).","triggerScenarios":"URLs like 'https://user:password@example.com/hook' or 'https://token@example.com/hook' passed to validateSyntax/uri.","commonSituations":"User pastes an authenticated URL from a browser or API tool (curl basic-auth style) into webhook config; attempt to smuggle credentials or inject '@' tricks (user-info SSRF bypass like https://expected.com@evil.com).","solutions":["Remove the user:pass@ section from the URL; authenticate instead via headers/tokens configured separately on the receiver","If the receiver needs auth, use a URL query token or webhook signing secret supported by the platform","Be aware this also blocks '@'-based SSRF bypasses — supply the real host only"],"exampleFix":"// before\nvalidator.validateSyntax(\"https://admin:secret@example.com/webhook\");\n// after\nvalidator.validateSyntax(\"https://example.com/webhook\"); // auth via header/token","handlingStrategy":"validation","validationCode":"if (url.contains(\"@\") && url.contains(\"://\")) reject(url); // or check URI.getRawUserInfo()","typeGuard":"boolean hasNoUserInfo(java.net.URI uri) { return uri.getRawUserInfo() == null; }","tryCatchPattern":"try { WebhookUrlValidator.validateSyntax(url); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"user info\")) { reject credentials-in-URL; } }","preventionTips":["Pass auth via headers or webhook signing secrets, never in the URL","Beware '@' SSRF bypass forms like https://trusted.com@evil.com — the validator blocks them by design","Strip user info from URLs copied from curl/browser history"],"tags":["java","webhook","security","credentials"],"backgroundTag":"invalid-url-format","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}