{"version": "2.1.0", "$schema": "https://json.schemastore.org/sarif-2.1.0.json", "runs": [{"tool": {"driver": {"name": "Repobility", "informationUri": "https://repobility.com", "rules": [{"id": "AUC001", "name": "[AUC001] No Repobility access matrix policy found: The repository uses web/API frameworks but does not define .repobilit", "shortDescription": {"text": "[AUC001] No Repobility access matrix policy found: The repository uses web/API frameworks but does not define .repobility/access.yml or equivalent authorization documentation."}, "fullDescription": {"text": "Add .repobility/access.yml mapping routes to anonymous, authenticated, owner, admin, and super_admin. Keep business-specific rules in the repo so CI can enforce them."}, "properties": {"scanner": "repobility-access-control", "category": "auth", "severity": "medium", "confidence": 0.92, "cwe": "", "owasp": ""}}, {"id": "DKR001", "name": "Docker final stage has no non-root USER", "shortDescription": {"text": "Docker final stage has no non-root USER"}, "fullDescription": {"text": "Add a non-root USER in the final runtime stage after files and permissions are prepared."}, "properties": {"scanner": "repobility-docker", "category": "docker", "severity": "medium", "confidence": 0.82, "cwe": "", "owasp": ""}}, {"id": "DKR017", "name": "Dockerfile installs dependencies after copying the full source tree", "shortDescription": {"text": "Dockerfile installs dependencies after copying the full source tree"}, "fullDescription": {"text": "Copy dependency manifests first, install dependencies in a cached layer, then copy the rest of the source tree."}, "properties": {"scanner": "repobility-docker", "category": "docker", "severity": "medium", "confidence": 0.9, "cwe": "", "owasp": ""}}, {"id": "DKR007", "name": "Docker build context has no .dockerignore", "shortDescription": {"text": "Docker build context has no .dockerignore"}, "fullDescription": {"text": "Add .dockerignore with at least .git, .env, private keys, dependency folders, build outputs, and local databases."}, "properties": {"scanner": "repobility-docker", "category": "docker", "severity": "medium", "confidence": 0.9, "cwe": "", "owasp": ""}}, {"id": "CFG006", "name": "[CFG006] Missing .gitignore: No .gitignore file. Risk of committing secrets and build artifacts.", "shortDescription": {"text": "[CFG006] Missing .gitignore: No .gitignore file. Risk of committing secrets and build artifacts."}, "fullDescription": {"text": "Add a .gitignore appropriate for your language/framework."}, "properties": {"scanner": "repobility-threat-engine", "category": "practices", "severity": "medium", "confidence": 1.0, "cwe": "", "owasp": ""}}, {"id": "AIC003", "name": "Duplicated implementation block across source files", "shortDescription": {"text": "Duplicated implementation block across source files"}, "fullDescription": {"text": "Extract the shared behavior into one function/module or delete the inactive duplicate after proving which path is used."}, "properties": {"scanner": "repobility-ai-code-hygiene", "category": "quality", "severity": "low", "confidence": 0.86, "cwe": "", "owasp": ""}}, {"id": "SEC020", "name": "[SEC020] Secret Printed to Logs: Debug or diagnostic code appears to print a credential-bearing value. This is a frequen", "shortDescription": {"text": "[SEC020] Secret Printed to Logs: Debug or diagnostic code appears to print a credential-bearing value. This is a frequent AI-assisted coding failure: the helper exposes the exact value needed for troubleshooting."}, "fullDescription": {"text": "Log only redacted, hashed, or last-four-style metadata. Rotate any secret that may have reached logs."}, "properties": {"scanner": "repobility-threat-engine", "category": "credential_exposure", "severity": "info", "confidence": 0.15, "cwe": "", "owasp": ""}}, {"id": "SEC036", "name": "[SEC036] HTTP Header Injection / CRLF Injection (and 4 more): Same pattern found in 4 additional files. Review if needed", "shortDescription": {"text": "[SEC036] HTTP Header Injection / CRLF Injection (and 4 more): Same pattern found in 4 additional files. Review if needed."}, "fullDescription": {"text": "Strip `\\r\\n` before setting headers:\n  safe = value.replace('\\r','').replace('\\n','')\n  response.headers['X-Custom'] = safe\nMost modern frameworks (Django 3+, Express 4.10+) already do this \u2014 but custom header-setting code often doesn't. Prefer framework methods (`response.set_cookie`) over manual header dict assignment."}, "properties": {"scanner": "repobility-threat-engine", "category": "injection", "severity": "info", "confidence": 0.2, "cwe": "", "owasp": ""}}, {"id": "SEC029", "name": "[SEC029] Server-Side Request Forgery (SSRF) \u2014 outbound HTTP from user input (and 5 more): Same pattern found in 5 additi", "shortDescription": {"text": "[SEC029] Server-Side Request Forgery (SSRF) \u2014 outbound HTTP from user input (and 5 more): Same pattern found in 5 additional files. Review if needed."}, "fullDescription": {"text": "Validate the URL against an allowlist BEFORE fetching:\n  ALLOWED = {'images.example.com', 'cdn.example.com'}\n  host = urlparse(url).hostname\n  if host not in ALLOWED: abort(400)\nOr use a server-side proxy (Imgproxy / serve-files-only-from-S3) that isolates outbound network access from the request handler.\nBlock private CIDRs explicitly: 10/8, 172.16/12, 192.168/16, 169.254/16."}, "properties": {"scanner": "repobility-threat-engine", "category": "ssrf", "severity": "info", "confidence": 0.2, "cwe": "", "owasp": ""}}, {"id": "DKR014", "name": "Dockerfile copies the entire context without .dockerignore", "shortDescription": {"text": "Dockerfile copies the entire context without .dockerignore"}, "fullDescription": {"text": "Create .dockerignore before using broad context copies, or copy only the required files and directories."}, "properties": {"scanner": "repobility-docker", "category": "docker", "severity": "high", "confidence": 0.92, "cwe": "", "owasp": ""}}, {"id": "DKR004", "name": "Docker build secret exposed through ARG", "shortDescription": {"text": "Docker build secret exposed through ARG"}, "fullDescription": {"text": "Replace secret ARG usage with `RUN --mount=type=secret,id=name ...` and pass the value with `docker build --secret`."}, "properties": {"scanner": "repobility-docker", "category": "docker", "severity": "high", "confidence": 0.86, "cwe": "", "owasp": ""}}]}}, "automationDetails": {"id": "repobility/481"}, "properties": {"repository": "calcom/cal.diy", "repoUrl": "https://github.com/calcom/cal.diy.git", "branch": "main"}, "results": [{"ruleId": "AUC001", "level": "warning", "message": {"text": "[AUC001] No Repobility access matrix policy found: The repository uses web/API frameworks but does not define .repobility/access.yml or equivalent authorization documentation."}, "properties": {"repobilityId": 28026, "scanner": "repobility-access-control", "fingerprint": "f1305052c3ba1e6c1cdb5dccc19e58a8168cf78b176658f32b1fc823df3e9d10", "category": "auth", "severity": "medium", "confidence": 0.92, "triageState": "open", "verdict": "likely", "isResolved": false, "reason": "Static route and framework evidence require project-owner confirmation.", "evidence": {"scanner": "repobility-access-control", "frameworks": ["Express", "Next.js"], "expected_files": [".repobility/access.yml", ".repobility/access.yaml", ".repobility/access.json", ".repobility/authorization.yml"], "correlation_key": "fp|f1305052c3ba1e6c1cdb5dccc19e58a8168cf78b176658f32b1fc823df3e9d10"}}}, {"ruleId": "DKR001", "level": "warning", "message": {"text": "Docker final stage has no non-root USER"}, "properties": {"repobilityId": 28025, "scanner": "repobility-docker", "fingerprint": "9b5ded04077fc370bb8a57c134e775950daf0ef8758937bbe278c1e1d524c38c", "category": "docker", "severity": "medium", "confidence": 0.82, "triageState": "open", "verdict": "likely", "isResolved": false, "reason": "No USER directive was found in the final runtime stage.", "evidence": {"rule_id": "DKR001", "scanner": "repobility-docker", "final_base": "node:20-alpine", "references": ["https://docs.docker.com/develop/develop-images/dockerfile_best-practices/", "https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html", "https://github.com/hadolint/hadolint"], "correlation_key": "fp|9b5ded04077fc370bb8a57c134e775950daf0ef8758937bbe278c1e1d524c38c"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/Dockerfile"}, "region": {"startLine": 1}}}]}, {"ruleId": "DKR017", "level": "warning", "message": {"text": "Dockerfile installs dependencies after copying the full source tree"}, "properties": {"repobilityId": 28024, "scanner": "repobility-docker", "fingerprint": "b39f3dcd1c0bec6035e13b53fbcab0f0cab860304499cd03ad300ddc205e5808", "category": "docker", "severity": "medium", "confidence": 0.9, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Broad context copy at line 17 appears before dependency installation.", "evidence": {"rule_id": "DKR017", "scanner": "repobility-docker", "references": ["https://docs.docker.com/develop/develop-images/dockerfile_best-practices/"], "broad_copy_line": 17, "correlation_key": "fp|b39f3dcd1c0bec6035e13b53fbcab0f0cab860304499cd03ad300ddc205e5808", "dependency_install_line": 19}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/Dockerfile"}, "region": {"startLine": 19}}}]}, {"ruleId": "DKR007", "level": "warning", "message": {"text": "Docker build context has no .dockerignore"}, "properties": {"repobilityId": 28022, "scanner": "repobility-docker", "fingerprint": "c98378cf8c37e4866e89d6ca06a24b7e8c44654aa34e6e4bf1367c4a4c0c5b44", "category": "docker", "severity": "medium", "confidence": 0.9, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Dockerfile exists but repository root has no .dockerignore.", "evidence": {"rule_id": "DKR007", "scanner": "repobility-docker", "references": ["https://docs.docker.com/develop/develop-images/dockerfile_best-practices/"], "correlation_key": "fp|c98378cf8c37e4866e89d6ca06a24b7e8c44654aa34e6e4bf1367c4a4c0c5b44"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".dockerignore"}, "region": {"startLine": 1}}}]}, {"ruleId": "DKR001", "level": "warning", "message": {"text": "Docker final stage has no non-root USER"}, "properties": {"repobilityId": 28021, "scanner": "repobility-docker", "fingerprint": "58fed6ef3e7fd55de965a0afd1e11fcefc9b413dea1b2abbebb01bd9e5995b08", "category": "docker", "severity": "medium", "confidence": 0.82, "triageState": "open", "verdict": "likely", "isResolved": false, "reason": "No USER directive was found in the final runtime stage.", "evidence": {"rule_id": "DKR001", "scanner": "repobility-docker", "final_base": "node:20", "references": ["https://docs.docker.com/develop/develop-images/dockerfile_best-practices/", "https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html", "https://github.com/hadolint/hadolint"], "correlation_key": "fp|58fed6ef3e7fd55de965a0afd1e11fcefc9b413dea1b2abbebb01bd9e5995b08"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "Dockerfile"}, "region": {"startLine": 77}}}]}, {"ruleId": "CFG006", "level": "warning", "message": {"text": "[CFG006] Missing .gitignore: No .gitignore file. Risk of committing secrets and build artifacts."}, "properties": {"repobilityId": 28011, "scanner": "repobility-threat-engine", "fingerprint": "c65fc71ce58c37a0e07837c0fe294108b731c43ef16027a2f0971c757bbe9a16", "category": "practices", "severity": "medium", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "No .gitignore file found in repository root", "evidence": {"reason": "No .gitignore file found in repository root", "rule_id": "CFG006", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "repo|practices|cfg006"}}}, {"ruleId": "AIC003", "level": "note", "message": {"text": "Duplicated implementation block across source files"}, "properties": {"repobilityId": 28019, "scanner": "repobility-ai-code-hygiene", "fingerprint": "b961a3f9914705f682d99ea6ecf808bbedca0422900a04c5ea46c935182f395e", "category": "quality", "severity": "low", "confidence": 0.86, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "A normalized source-code window appears in two different non-test files.", "evidence": {"lines": 12, "rule_id": "AIC003", "scanner": "repobility-ai-code-hygiene", "references": ["https://jscpd.dev/"], "duplicate_file": "apps/api/v2/src/modules/destination-calendars/controllers/destination-calendars.controller.e2e-spec.ts", "duplicate_line": 24, "correlation_key": "fp|b961a3f9914705f682d99ea6ecf808bbedca0422900a04c5ea46c935182f395e"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/modules/selected-calendars/controllers/selected-calendars.controller.e2e-spec.ts"}, "region": {"startLine": 24}}}]}, {"ruleId": "AIC003", "level": "note", "message": {"text": "Duplicated implementation block across source files"}, "properties": {"repobilityId": 28018, "scanner": "repobility-ai-code-hygiene", "fingerprint": "f794ded74a98de244fcb2601e7f6e89682f8de7c7f07d2a7a12568e2f062842e", "category": "quality", "severity": "low", "confidence": 0.86, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "A normalized source-code window appears in two different non-test files.", "evidence": {"lines": 12, "rule_id": "AIC003", "scanner": "repobility-ai-code-hygiene", "references": ["https://jscpd.dev/"], "duplicate_file": "apps/api/v2/src/modules/prisma/prisma-worker.module.ts", "duplicate_line": 1, "correlation_key": "fp|f794ded74a98de244fcb2601e7f6e89682f8de7c7f07d2a7a12568e2f062842e"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/modules/prisma/prisma.module.ts"}, "region": {"startLine": 1}}}]}, {"ruleId": "AIC003", "level": "note", "message": {"text": "Duplicated implementation block across source files"}, "properties": {"repobilityId": 28017, "scanner": "repobility-ai-code-hygiene", "fingerprint": "c8987406dfd801d22301013c71c90ac3d62060433b4e60928c027e110a0753f2", "category": "quality", "severity": "low", "confidence": 0.86, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "A normalized source-code window appears in two different non-test files.", "evidence": {"lines": 12, "rule_id": "AIC003", "scanner": "repobility-ai-code-hygiene", "references": ["https://jscpd.dev/"], "duplicate_file": "apps/api/v2/src/modules/prisma/prisma-read.service.ts", "duplicate_line": 42, "correlation_key": "fp|c8987406dfd801d22301013c71c90ac3d62060433b4e60928c027e110a0753f2"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/modules/prisma/prisma-write.service.ts"}, "region": {"startLine": 49}}}]}, {"ruleId": "AIC003", "level": "note", "message": {"text": "Duplicated implementation block across source files"}, "properties": {"repobilityId": 28016, "scanner": "repobility-ai-code-hygiene", "fingerprint": "baac848f1cbc99e7f5883073550598b62096b00dd16c82bf8d72e87e6ce02ea2", "category": "quality", "severity": "low", "confidence": 0.86, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "A normalized source-code window appears in two different non-test files.", "evidence": {"lines": 12, "rule_id": "AIC003", "scanner": "repobility-ai-code-hygiene", "references": ["https://jscpd.dev/"], "duplicate_file": "apps/api/v2/src/modules/event-types/controllers/event-types-webhooks.controller.e2e-spec.ts", "duplicate_line": 98, "correlation_key": "fp|baac848f1cbc99e7f5883073550598b62096b00dd16c82bf8d72e87e6ce02ea2"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-webhooks/oauth-client-webhooks.controller.e2e-spec.ts"}, "region": {"startLine": 168}}}]}, {"ruleId": "AIC003", "level": "note", "message": {"text": "Duplicated implementation block across source files"}, "properties": {"repobilityId": 28015, "scanner": "repobility-ai-code-hygiene", "fingerprint": "9b01735a9d05c17b349bf70e9998ae75fcef98b55c454f5352de98ae48012192", "category": "quality", "severity": "low", "confidence": 0.86, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "A normalized source-code window appears in two different non-test files.", "evidence": {"lines": 12, "rule_id": "AIC003", "scanner": "repobility-ai-code-hygiene", "references": ["https://jscpd.dev/"], "duplicate_file": "apps/api/v2/src/modules/kysely/kysely-read.service.ts", "duplicate_line": 13, "correlation_key": "fp|9b01735a9d05c17b349bf70e9998ae75fcef98b55c454f5352de98ae48012192"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/modules/kysely/kysely-write.service.ts"}, "region": {"startLine": 13}}}]}, {"ruleId": "AIC003", "level": "note", "message": {"text": "Duplicated implementation block across source files"}, "properties": {"repobilityId": 28014, "scanner": "repobility-ai-code-hygiene", "fingerprint": "3ec4e18da9127b99df934a53e1f05a97a93737673f4b5f65c77e7f7d4545813f", "category": "quality", "severity": "low", "confidence": 0.86, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "A normalized source-code window appears in two different non-test files.", "evidence": {"lines": 12, "rule_id": "AIC003", "scanner": "repobility-ai-code-hygiene", "references": ["https://jscpd.dev/"], "duplicate_file": "apps/api/v2/src/modules/cal-unified-calendars/inputs/update-unified-calendar-event.input.ts", "duplicate_line": 31, "correlation_key": "fp|3ec4e18da9127b99df934a53e1f05a97a93737673f4b5f65c77e7f7d4545813f"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/modules/cal-unified-calendars/outputs/get-unified-calendar-event.output.ts"}, "region": {"startLine": 232}}}]}, {"ruleId": "AIC003", "level": "note", "message": {"text": "Duplicated implementation block across source files"}, "properties": {"repobilityId": 28013, "scanner": "repobility-ai-code-hygiene", "fingerprint": "f8c013616359c28e462e61705bbc8442647bf1cc00e4a80bd9d37b64c082596a", "category": "quality", "severity": "low", "confidence": 0.86, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "A normalized source-code window appears in two different non-test files.", "evidence": {"lines": 12, "rule_id": "AIC003", "scanner": "repobility-ai-code-hygiene", "references": ["https://jscpd.dev/"], "duplicate_file": "apps/api/v2/src/modules/auth/decorators/get-optional-user/get-optional-user.decorator.ts", "duplicate_line": 13, "correlation_key": "fp|f8c013616359c28e462e61705bbc8442647bf1cc00e4a80bd9d37b64c082596a"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/modules/auth/decorators/get-user/get-user.decorator.ts"}, "region": {"startLine": 12}}}]}, {"ruleId": "AIC003", "level": "note", "message": {"text": "Duplicated implementation block across source files"}, "properties": {"repobilityId": 28012, "scanner": "repobility-ai-code-hygiene", "fingerprint": "a7c09015bf812cdf9bf8cdae6e6befc14ab212c6aede6d92e33d7f6e02e52a3b", "category": "quality", "severity": "low", "confidence": 0.86, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "A normalized source-code window appears in two different non-test files.", "evidence": {"lines": 12, "rule_id": "AIC003", "scanner": "repobility-ai-code-hygiene", "references": ["https://jscpd.dev/"], "duplicate_file": "apps/api/v2/src/filters/http-exception.filter.ts", "duplicate_line": 19, "correlation_key": "fp|a7c09015bf812cdf9bf8cdae6e6befc14ab212c6aede6d92e33d7f6e02e52a3b"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/filters/trpc-exception.filter.ts"}, "region": {"startLine": 111}}}]}, {"ruleId": "SEC020", "level": "none", "message": {"text": "[SEC020] Secret Printed to Logs: Debug or diagnostic code appears to print a credential-bearing value. This is a frequent AI-assisted coding failure: the helper exposes the exact value needed for troubleshooting."}, "properties": {"repobilityId": 28010, "scanner": "repobility-threat-engine", "fingerprint": "18b75b896a03324f32d6f7471c5a2b5234e82bb3c8ed6c8ef0e627ab02186b82", "category": "credential_exposure", "severity": "info", "confidence": 0.15, "triageState": "false_positive", "verdict": "likely_fp", "isResolved": true, "reason": "Log message mentions credential-related metadata but does not print a credential-bearing value", "evidence": {"match": "logger.warn(`Token for ${ownerId} had no expiry time, assuming it's new.`)", "reason": "Log message mentions credential-related metadata but does not print a credential-bearing value", "rule_id": "SEC020", "scanner": "repobility-threat-engine", "confidence": 0.15, "correlation_key": "secret|token|2|logger.warn token for ownerid had no expiry time assuming it s new."}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/modules/oauth-clients/services/oauth-flow.service.ts"}, "region": {"startLine": 30}}}]}, {"ruleId": "SEC020", "level": "none", "message": {"text": "[SEC020] Secret Printed to Logs: Debug or diagnostic code appears to print a credential-bearing value. This is a frequent AI-assisted coding failure: the helper exposes the exact value needed for troubleshooting."}, "properties": {"repobilityId": 28009, "scanner": "repobility-threat-engine", "fingerprint": "ae4c3392afb8d2a8347de8588edc7e405ac0b1e9672dde23c8c50c910e80c16d", "category": "credential_exposure", "severity": "info", "confidence": 0.15, "triageState": "false_positive", "verdict": "likely_fp", "isResolved": true, "reason": "Log message mentions credential-related metadata but does not print a credential-bearing value", "evidence": {"match": "logger.log(`Forcing new access tokens for managed user with ID ${userId}`)", "reason": "Log message mentions credential-related metadata but does not print a credential-bearing value", "rule_id": "SEC020", "scanner": "repobility-threat-engine", "confidence": 0.15, "correlation_key": "secret|token|19|logger.log forcing new access tokens for managed user with id userid"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller.ts"}, "region": {"startLine": 192}}}]}, {"ruleId": "SEC036", "level": "none", "message": {"text": "[SEC036] HTTP Header Injection / CRLF Injection (and 4 more): Same pattern found in 4 additional files. Review if needed."}, "properties": {"repobilityId": 28008, "scanner": "repobility-threat-engine", "fingerprint": "324c61174b76108a9f8b3b431fafef3145e5c816d612e7edaa12f7e3405c4dbf", "category": "injection", "severity": "info", "confidence": 0.2, "triageState": "false_positive", "verdict": "likely_fp", "isResolved": true, "reason": "Deduplicated summary only: 4 additional occurrences found. The top occurrences remain visible as actionable findings.", "evidence": {"reason": "Deduplicated summary only: 4 additional occurrences found. The top occurrences remain visible as actionable findings.", "rule_id": "SEC036", "scanner": "repobility-threat-engine", "confidence": 0.2, "correlation_key": "fp|324c61174b76108a9f8b3b431fafef3145e5c816d612e7edaa12f7e3405c4dbf"}}}, {"ruleId": "SEC029", "level": "none", "message": {"text": "[SEC029] Server-Side Request Forgery (SSRF) \u2014 outbound HTTP from user input (and 5 more): Same pattern found in 5 additional files. Review if needed."}, "properties": {"repobilityId": 28004, "scanner": "repobility-threat-engine", "fingerprint": "4a4f0807e4b2a602904c2c23d95abb6f9e09448ebf29c9e0a18b9da6a89476f2", "category": "ssrf", "severity": "info", "confidence": 0.2, "triageState": "false_positive", "verdict": "likely_fp", "isResolved": true, "reason": "Deduplicated summary only: 5 additional occurrences found. The top occurrences remain visible as actionable findings.", "evidence": {"reason": "Deduplicated summary only: 5 additional occurrences found. The top occurrences remain visible as actionable findings.", "rule_id": "SEC029", "scanner": "repobility-threat-engine", "confidence": 0.2, "correlation_key": "fp|4a4f0807e4b2a602904c2c23d95abb6f9e09448ebf29c9e0a18b9da6a89476f2"}}}, {"ruleId": "DKR014", "level": "error", "message": {"text": "Dockerfile copies the entire context without .dockerignore"}, "properties": {"repobilityId": 28023, "scanner": "repobility-docker", "fingerprint": "4ef38e59d2cd3eabb496601a0962a8aa971b820e41a7131ab37b8ed60c703b22", "category": "docker", "severity": "high", "confidence": 0.92, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Broad context copy and missing .dockerignore were found together.", "evidence": {"rule_id": "DKR014", "scanner": "repobility-docker", "references": ["https://docs.docker.com/develop/develop-images/dockerfile_best-practices/"], "correlation_key": "fp|4ef38e59d2cd3eabb496601a0962a8aa971b820e41a7131ab37b8ed60c703b22"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/Dockerfile"}, "region": {"startLine": 17}}}]}, {"ruleId": "DKR004", "level": "error", "message": {"text": "Docker build secret exposed through ARG"}, "properties": {"repobilityId": 28020, "scanner": "repobility-docker", "fingerprint": "a99656f9191d293ce51cd316b83f6c103b5f7503a6a1ae11281aa1da0a232fc4", "category": "docker", "severity": "high", "confidence": 0.86, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "ARG name looks secret-bearing; BuildKit secret mounts are the safer pattern.", "evidence": {"rule_id": "DKR004", "scanner": "repobility-docker", "variable": "NEXTAUTH_SECRET", "references": ["https://docs.docker.com/build/building/secrets/", "https://github.com/hadolint/hadolint"], "correlation_key": "fp|a99656f9191d293ce51cd316b83f6c103b5f7503a6a1ae11281aa1da0a232fc4"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "Dockerfile"}, "region": {"startLine": 11}}}]}, {"ruleId": "SEC036", "level": "error", "message": {"text": "[SEC036] HTTP Header Injection / CRLF Injection: Setting an HTTP response header from user input without stripping CRLF lets attackers inject extra headers (Set-Cookie, etc.) or split the response. Real CVEs: CVE-2017-15193 (Mahara), CVE-2019-11358 (Django), CVE-2020-26116 (Python http.client). CWE-93/113."}, "properties": {"repobilityId": 28007, "scanner": "repobility-threat-engine", "fingerprint": "23975737c6e251947e1ad5eb20b4999b072175514a99ceceba90390c2ab2b089", "category": "injection", "severity": "high", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Pattern matched with no mitigating context found", "evidence": {"match": "response.setHeader(\"X-Request-Id\", request", "reason": "Pattern matched with no mitigating context found", "rule_id": "SEC036", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "code|injection|token|39|sec036"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/filters/prisma-exception.filter.ts"}, "region": {"startLine": 39}}}]}, {"ruleId": "SEC036", "level": "error", "message": {"text": "[SEC036] HTTP Header Injection / CRLF Injection: Setting an HTTP response header from user input without stripping CRLF lets attackers inject extra headers (Set-Cookie, etc.) or split the response. Real CVEs: CVE-2017-15193 (Mahara), CVE-2019-11358 (Django), CVE-2020-26116 (Python http.client). CWE-93/113."}, "properties": {"repobilityId": 28006, "scanner": "repobility-threat-engine", "fingerprint": "4bdc2350bcfd657704c877246c2c2f7c5bcf1888a58b4c158f3bbf04ea8fd3b6", "category": "injection", "severity": "high", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Pattern matched with no mitigating context found", "evidence": {"match": "response.setHeader(\"X-Request-Id\", request", "reason": "Pattern matched with no mitigating context found", "rule_id": "SEC036", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "code|injection|token|19|sec036"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/filters/http-exception.filter.ts"}, "region": {"startLine": 19}}}]}, {"ruleId": "SEC036", "level": "error", "message": {"text": "[SEC036] HTTP Header Injection / CRLF Injection: Setting an HTTP response header from user input without stripping CRLF lets attackers inject extra headers (Set-Cookie, etc.) or split the response. Real CVEs: CVE-2017-15193 (Mahara), CVE-2019-11358 (Django), CVE-2020-26116 (Python http.client). CWE-93/113."}, "properties": {"repobilityId": 28005, "scanner": "repobility-threat-engine", "fingerprint": "2158833e742d1ce05ec6e631ddc6181ef4888ccba2430fc05745fda31b1d7d96", "category": "injection", "severity": "high", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Pattern matched with no mitigating context found", "evidence": {"match": "response.setHeader(\"X-Request-Id\", request", "reason": "Pattern matched with no mitigating context found", "rule_id": "SEC036", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "code|injection|token|41|sec036"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/filters/calendar-service-exception.filter.ts"}, "region": {"startLine": 41}}}]}, {"ruleId": "SEC029", "level": "error", "message": {"text": "[SEC029] Server-Side Request Forgery (SSRF) \u2014 outbound HTTP from user input: Outbound HTTP request to a user-controlled URL without allowlist validation. Attackers can probe internal services (169.254.169.254 metadata, internal Kubernetes endpoints, file:// URIs), exfiltrate data, or pivot through your network. SSRF is OWASP A10:2021 and a frequent foothold in cloud breaches."}, "properties": {"repobilityId": 28003, "scanner": "repobility-threat-engine", "fingerprint": "faf0d44a30e52838e87b048136809df568cf81689365fd68a81200191f2b6c21", "category": "ssrf", "severity": "high", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Pattern matched with no mitigating context found", "evidence": {"match": "Url(r", "reason": "Pattern matched with no mitigating context found", "rule_id": "SEC029", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "fp|faf0d44a30e52838e87b048136809df568cf81689365fd68a81200191f2b6c21"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/modules/auth/oauth2/services/oauth2-error.service.ts"}, "region": {"startLine": 36}}}]}, {"ruleId": "SEC029", "level": "error", "message": {"text": "[SEC029] Server-Side Request Forgery (SSRF) \u2014 outbound HTTP from user input: Outbound HTTP request to a user-controlled URL without allowlist validation. Attackers can probe internal services (169.254.169.254 metadata, internal Kubernetes endpoints, file:// URIs), exfiltrate data, or pivot through your network. SSRF is OWASP A10:2021 and a frequent foothold in cloud breaches."}, "properties": {"repobilityId": 28002, "scanner": "repobility-threat-engine", "fingerprint": "373dfae05a7c40bfe0fd34701e7eb06673038752014e7b57b362a4381605d69d", "category": "ssrf", "severity": "high", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Pattern matched with no mitigating context found", "evidence": {"match": "URL(r", "reason": "Pattern matched with no mitigating context found", "rule_id": "SEC029", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "fp|373dfae05a7c40bfe0fd34701e7eb06673038752014e7b57b362a4381605d69d"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/v2/src/modules/auth/oauth2/controllers/oauth2.controller.e2e-spec.ts"}, "region": {"startLine": 105}}}]}, {"ruleId": "SEC029", "level": "error", "message": {"text": "[SEC029] Server-Side Request Forgery (SSRF) \u2014 outbound HTTP from user input: Outbound HTTP request to a user-controlled URL without allowlist validation. Attackers can probe internal services (169.254.169.254 metadata, internal Kubernetes endpoints, file:// URIs), exfiltrate data, or pivot through your network. SSRF is OWASP A10:2021 and a frequent foothold in cloud breaches."}, "properties": {"repobilityId": 28001, "scanner": "repobility-threat-engine", "fingerprint": "48f826fc355c14bfabf1ea08e905cddd7e49cb01eff93140469546efeb383304", "category": "ssrf", "severity": "high", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Pattern matched with no mitigating context found", "evidence": {"match": "url(r", "reason": "Pattern matched with no mitigating context found", "rule_id": "SEC029", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "fp|48f826fc355c14bfabf1ea08e905cddd7e49cb01eff93140469546efeb383304"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".snaplet/transform.ts"}, "region": {"startLine": 208}}}]}]}]}