Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@
**Vulnerability:** The `filterSensitiveFields` function in `src/providers/index.ts` used a manual recursive loop to drop sensitive keys, but it failed to recurse into arrays. If a configuration object contained an array with sensitive nested objects, those secrets would be leaked in debug logs.
**Learning:** Manual object traversal for redaction is prone to edge cases (like arrays or circular references).
**Prevention:** Use a custom replacer function with `JSON.stringify` to safely and completely redact sensitive fields across all nested structures.

## 2026-06-29 - Insufficient Broad Pattern Matching for Secrets
**Vulnerability:** The `SENSITIVE_KEY_PATTERNS` array used for redacting sensitive fields did not include patterns for `bearer`, `session`, `jwt`, and `cookie`. Any of these authentication tokens passed within headers or configuration would be logged in plaintext in error logs and debug outputs.
**Learning:** Hardcoded allowlists or blocklists for secrets need to be comprehensive and cover a wide variety of standard authentication schemes.
**Prevention:** Regularly audit redaction pattern lists against modern authentication methods (like JWTs, bearer tokens, and session cookies).
4 changes: 4 additions & 0 deletions src/sensitive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ const SENSITIVE_KEY_PATTERNS = [
"auth",
"credential",
"authorization",
"bearer",
"session",
"jwt",
"cookie",
];

export function isSensitiveKey(key: string): boolean {
Expand Down
12 changes: 12 additions & 0 deletions tests/security.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ describe("security", () => {
expect(isSensitiveKey("x-api-token")).toBe(true);
expect(isSensitiveKey("clientSecret")).toBe(true);
expect(isSensitiveKey("credentialRef")).toBe(true);
expect(isSensitiveKey("bearerToken")).toBe(true);
expect(isSensitiveKey("session_id")).toBe(true);
expect(isSensitiveKey("jwt_payload")).toBe(true);
expect(isSensitiveKey("cookie")).toBe(true);
expect(isSensitiveKey("Content-Type")).toBe(false);
});

Expand Down Expand Up @@ -171,6 +175,10 @@ describe("security", () => {
access_token: "should-be-filtered",
apiKey: "should-be-filtered",
clientSecret: "should-be-filtered",
bearer_token: "should-be-filtered",
session_id: "should-be-filtered",
jwt_token: "should-be-filtered",
cookie: "should-be-filtered",
normal_field: "should-remain",
base_url: "should-remain",
};
Expand All @@ -187,6 +195,10 @@ describe("security", () => {
expect(filtered).not.toHaveProperty("access_token");
expect(filtered).not.toHaveProperty("apiKey");
expect(filtered).not.toHaveProperty("clientSecret");
expect(filtered).not.toHaveProperty("bearer_token");
expect(filtered).not.toHaveProperty("session_id");
expect(filtered).not.toHaveProperty("jwt_token");
expect(filtered).not.toHaveProperty("cookie");
});

it("should be case-insensitive", () => {
Expand Down