{"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": "DKR001", "name": "Docker final stage has no non-root USER", "shortDescription": {"text": "Docker final stage has no non-root USER"}, "fullDescription": {"text": "Docker images run as root unless the image or Dockerfile switches to a non-root user."}, "properties": {"scanner": "repobility-docker", "category": "docker", "severity": "medium", "confidence": 0.82, "cwe": "", "owasp": ""}}, {"id": "DKR007", "name": "Docker build context has no .dockerignore", "shortDescription": {"text": "Docker build context has no .dockerignore"}, "fullDescription": {"text": "Without .dockerignore, build context can include source history, local env files, dependencies, and generated artifacts."}, "properties": {"scanner": "repobility-docker", "category": "docker", "severity": "medium", "confidence": 0.9, "cwe": "", "owasp": ""}}, {"id": "SEC017", "name": "[SEC017] Unbounded Input to LLM/External API: User input is passed to an LLM or external AI API (OpenAI, Anthropic, etc.", "shortDescription": {"text": "[SEC017] Unbounded Input to LLM/External API: User input is passed to an LLM or external AI API (OpenAI, Anthropic, etc.) without any visible length or size validation. This creates two risks: (1) Cost abuse \u2014 an attacker can send extremely"}, "fullDescription": {"text": "1) Enforce a maximum input length BEFORE sending to the API: e.g. `if len(text) > 4000: return error`. 2) Use token counting (tiktoken for OpenAI, anthropic's token counter) to enforce token-level limits. 3) Set max_tokens on the API call to cap response cost. 4) Add rate limiting per user/IP to prevent automated abuse. 5) Monitor API spend with alerts for unusual usage patterns."}, "properties": {"scanner": "repobility-threat-engine", "category": "llm_injection", "severity": "medium", "confidence": 0.8, "cwe": "", "owasp": ""}}, {"id": "SEC007", "name": "[SEC007] Unsafe Deserialization: Unsafe deserialization can execute arbitrary code.", "shortDescription": {"text": "[SEC007] Unsafe Deserialization: Unsafe deserialization can execute arbitrary code."}, "fullDescription": {"text": "Use yaml.safe_load() instead of yaml.load(). Avoid pickle for untrusted data."}, "properties": {"scanner": "repobility-threat-engine", "category": "deserialization", "severity": "medium", "confidence": 1.0, "cwe": "", "owasp": ""}}, {"id": "ERR002", "name": "[ERR002] Empty Catch Block: Empty catch blocks hide errors.", "shortDescription": {"text": "[ERR002] Empty Catch Block: Empty catch blocks hide errors."}, "fullDescription": {"text": "Log the error or rethrow it. Use console.error() at minimum."}, "properties": {"scanner": "repobility-threat-engine", "category": "error_handling", "severity": "medium", "confidence": 1.0, "cwe": "", "owasp": ""}}, {"id": "SEC015", "name": "[SEC015] Insecure Randomness for Security: Weak PRNG used in security-sensitive context. Output is predictable.", "shortDescription": {"text": "[SEC015] Insecure Randomness for Security: Weak PRNG used in security-sensitive context. Output is predictable."}, "fullDescription": {"text": "Use secrets module (Python) or crypto.getRandomValues() (JS) for security-sensitive randomness."}, "properties": {"scanner": "repobility-threat-engine", "category": "crypto", "severity": "medium", "confidence": 1.0, "cwe": "", "owasp": ""}}, {"id": "SEC006", "name": "[SEC006] XSS Risk: Direct HTML injection without sanitization.", "shortDescription": {"text": "[SEC006] XSS Risk: Direct HTML injection without sanitization."}, "fullDescription": {"text": "Use textContent instead of innerHTML. Sanitize with DOMPurify."}, "properties": {"scanner": "repobility-threat-engine", "category": "injection", "severity": "low", "confidence": 0.4, "cwe": "", "owasp": ""}}]}}, "automationDetails": {"id": "repobility/336"}, "properties": {"repository": "bytedance/UI-TARS-desktop", "repoUrl": "https://github.com/bytedance/UI-TARS-desktop", "branch": "main"}, "results": [{"ruleId": "DKR001", "level": "warning", "message": {"text": "Docker final stage has no non-root USER"}, "properties": {"repobilityId": 10632, "scanner": "repobility-docker", "fingerprint": "538e588724f40abe5d388e5aa7e1b39f40a0799538bdb1dceaade74ac26737f1", "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:22-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|538e588724f40abe5d388e5aa7e1b39f40a0799538bdb1dceaade74ac26737f1"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "packages/agent-infra/mcp-servers/filesystem/Dockerfile"}, "region": {"startLine": 13}}}]}, {"ruleId": "DKR007", "level": "warning", "message": {"text": "Docker build context has no .dockerignore"}, "properties": {"repobilityId": 10631, "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": "SEC017", "level": "warning", "message": {"text": "[SEC017] Unbounded Input to LLM/External API: User input is passed to an LLM or external AI API (OpenAI, Anthropic, etc.) without any visible length or size validation. This creates two risks: (1) Cost abuse \u2014 an attacker can send extremely long inputs to burn through your API credits (a single 128K-token request to GPT-4 costs ~$4, and automated attacks can drain budgets in minutes). (2) Context stuffing \u2014 oversized inputs can push your system prompt out of the context window, effectively disab"}, "properties": {"repobilityId": 10629, "scanner": "repobility-threat-engine", "fingerprint": "6c1885e87c2fc6ca5ececc194525c6e53ff782a587d46ae6332843569946cb9f", "category": "llm_injection", "severity": "medium", "confidence": 0.8, "triageState": "open", "verdict": "likely", "isResolved": false, "reason": "User input is passed to an AI/LLM API with no visible length check or rate limit. An attacker can send extremely long inputs to: (1) drain your API budget (128K tokens to GPT-4 \u2248 $4/request, automated = thousands of dollars), (2) push your system prompt out of the context window, disabling safety guardrails. Add input length validation before the API call.", "evidence": {"match": "Llm.invoke(input", "reason": "User input is passed to an AI/LLM API with no visible length check or rate limit. An attacker can send extremely long inputs to: (1) drain your API budget (128K tokens to GPT-4 \u2248 $4/request, automated = thousands of dollars), (2) push your system prompt out of the context window, disabling safety guardrails. Add input length validation before the API call.", "rule_id": "SEC017", "scanner": "repobility-threat-engine", "confidence": 0.8, "correlation_key": "fp|6c1885e87c2fc6ca5ececc194525c6e53ff782a587d46ae6332843569946cb9f"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "packages/agent-infra/browser-use/src/agent/agents/navigator.ts"}, "region": {"startLine": 97}}}]}, {"ruleId": "SEC017", "level": "warning", "message": {"text": "[SEC017] Unbounded Input to LLM/External API: User input is passed to an LLM or external AI API (OpenAI, Anthropic, etc.) without any visible length or size validation. This creates two risks: (1) Cost abuse \u2014 an attacker can send extremely long inputs to burn through your API credits (a single 128K-token request to GPT-4 costs ~$4, and automated attacks can drain budgets in minutes). (2) Context stuffing \u2014 oversized inputs can push your system prompt out of the context window, effectively disab"}, "properties": {"repobilityId": 10628, "scanner": "repobility-threat-engine", "fingerprint": "10eace16fdb2e0f5bd0c0ca429a03853fb99114efd57929562f5474b77108250", "category": "llm_injection", "severity": "medium", "confidence": 0.8, "triageState": "open", "verdict": "likely", "isResolved": false, "reason": "User input is passed to an AI/LLM API with no visible length check or rate limit. An attacker can send extremely long inputs to: (1) drain your API budget (128K tokens to GPT-4 \u2248 $4/request, automated = thousands of dollars), (2) push your system prompt out of the context window, disabling safety guardrails. Add input length validation before the API call.", "evidence": {"match": "Llm.invoke(input", "reason": "User input is passed to an AI/LLM API with no visible length check or rate limit. An attacker can send extremely long inputs to: (1) drain your API budget (128K tokens to GPT-4 \u2248 $4/request, automated = thousands of dollars), (2) push your system prompt out of the context window, disabling safety guardrails. Add input length validation before the API call.", "rule_id": "SEC017", "scanner": "repobility-threat-engine", "confidence": 0.8, "correlation_key": "fp|10eace16fdb2e0f5bd0c0ca429a03853fb99114efd57929562f5474b77108250"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "packages/agent-infra/browser-use/src/agent/agents/base.ts"}, "region": {"startLine": 142}}}]}, {"ruleId": "SEC007", "level": "warning", "message": {"text": "[SEC007] Unsafe Deserialization: Unsafe deserialization can execute arbitrary code."}, "properties": {"repobilityId": 10627, "scanner": "repobility-threat-engine", "fingerprint": "3ae987d0d30dcc8ffac003301a9083330766fcf200823e2a26f1eba5a8a5bc9e", "category": "deserialization", "severity": "medium", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Pattern matched with no mitigating context found", "evidence": {"match": "yaml.load(", "reason": "Pattern matched with no mitigating context found", "rule_id": "SEC007", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "code|deserialization|token|40|sec007"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "packages/ui-tars/cli/src/cli/start.ts"}, "region": {"startLine": 40}}}]}, {"ruleId": "SEC007", "level": "warning", "message": {"text": "[SEC007] Unsafe Deserialization: Unsafe deserialization can execute arbitrary code."}, "properties": {"repobilityId": 10626, "scanner": "repobility-threat-engine", "fingerprint": "0f19e15808e9f8d4d2ce97cf1d41bbe6bc162d4c5c0d5d18d919a83124dccf47", "category": "deserialization", "severity": "medium", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Pattern matched with no mitigating context found", "evidence": {"match": "yaml.load(", "reason": "Pattern matched with no mitigating context found", "rule_id": "SEC007", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "code|deserialization|token|25|sec007"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "scripts/merge-yml/merge-yml.ts"}, "region": {"startLine": 25}}}]}, {"ruleId": "SEC007", "level": "warning", "message": {"text": "[SEC007] Unsafe Deserialization: Unsafe deserialization can execute arbitrary code."}, "properties": {"repobilityId": 10625, "scanner": "repobility-threat-engine", "fingerprint": "f4932eee6dd1baf2aeac9028744fa011c210ebbbb26d927d741e9ddfec8f7cfe", "category": "deserialization", "severity": "medium", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Pattern matched with no mitigating context found", "evidence": {"match": "yaml.load(", "reason": "Pattern matched with no mitigating context found", "rule_id": "SEC007", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "code|deserialization|token|100|sec007"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/ui-tars/src/main/store/setting.ts"}, "region": {"startLine": 100}}}]}, {"ruleId": "ERR002", "level": "warning", "message": {"text": "[ERR002] Empty Catch Block: Empty catch blocks hide errors."}, "properties": {"repobilityId": 10624, "scanner": "repobility-threat-engine", "fingerprint": "277fe080bf930d440ab785bb1d7b0dbebf07052f1d4f3722974cb1fab3b2dcbb", "category": "error_handling", "severity": "medium", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Pattern matched with no mitigating context found", "evidence": {"match": "catch (e) {}", "reason": "Pattern matched with no mitigating context found", "rule_id": "ERR002", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "fp|277fe080bf930d440ab785bb1d7b0dbebf07052f1d4f3722974cb1fab3b2dcbb"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "packages/agent-infra/browser/src/browser-finder/firefox-paths.ts"}, "region": {"startLine": 19}}}]}, {"ruleId": "ERR002", "level": "warning", "message": {"text": "[ERR002] Empty Catch Block: Empty catch blocks hide errors."}, "properties": {"repobilityId": 10623, "scanner": "repobility-threat-engine", "fingerprint": "8d2bba4e0ead6dd4d88f901a6f1e06875cbdee8ad3a9d041de9f16f2eb229fb6", "category": "error_handling", "severity": "medium", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Pattern matched with no mitigating context found", "evidence": {"match": "catch (e) {}", "reason": "Pattern matched with no mitigating context found", "rule_id": "ERR002", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "fp|8d2bba4e0ead6dd4d88f901a6f1e06875cbdee8ad3a9d041de9f16f2eb229fb6"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "packages/agent-infra/browser/src/browser-finder/chrome-paths.ts"}, "region": {"startLine": 40}}}]}, {"ruleId": "ERR002", "level": "warning", "message": {"text": "[ERR002] Empty Catch Block: Empty catch blocks hide errors."}, "properties": {"repobilityId": 10622, "scanner": "repobility-threat-engine", "fingerprint": "319056fb9fc621dabb00a647700b1fcd1464f542e4367554ec00bb0bab32637d", "category": "error_handling", "severity": "medium", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Pattern matched with no mitigating context found", "evidence": {"match": ".catch(() => {})", "reason": "Pattern matched with no mitigating context found", "rule_id": "ERR002", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "fp|319056fb9fc621dabb00a647700b1fcd1464f542e4367554ec00bb0bab32637d"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/ui-tars/src/renderer/src/pages/remote/cast/canvas.tsx"}, "region": {"startLine": 242}}}]}, {"ruleId": "SEC015", "level": "warning", "message": {"text": "[SEC015] Insecure Randomness for Security: Weak PRNG used in security-sensitive context. Output is predictable."}, "properties": {"repobilityId": 10618, "scanner": "repobility-threat-engine", "fingerprint": "39104dcf56b6c5f13127049d83799e499d6ed27306bdb815bce1a17f90abb7dc", "category": "crypto", "severity": "medium", "confidence": 1.0, "triageState": "open", "verdict": "confirmed", "isResolved": false, "reason": "Security-sensitive keyword found nearby \u2014 weak PRNG is risky here", "evidence": {"match": "Math.random()", "reason": "Security-sensitive keyword found nearby \u2014 weak PRNG is risky here", "rule_id": "SEC015", "scanner": "repobility-threat-engine", "confidence": 1.0, "correlation_key": "code|crypto|token|397|sec015"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "packages/ui-tars/operators/browser-operator/src/browser-operator.ts"}, "region": {"startLine": 397}}}]}, {"ruleId": "SEC006", "level": "note", "message": {"text": "[SEC006] XSS Risk: Direct HTML injection without sanitization."}, "properties": {"repobilityId": 10630, "scanner": "repobility-threat-engine", "fingerprint": "c3b3ef07a6e7b0f58bdc45d961cd62cdf12e261ef6d7b27907199eb4b31d1306", "category": "injection", "severity": "low", "confidence": 0.4, "triageState": "false_positive", "verdict": "likely_fp", "isResolved": true, "reason": "No user-input source (request/query/fetch/URL) found \u2014 may be static content", "evidence": {"match": ".innerHTML = `", "reason": "No user-input source (request/query/fetch/URL) found \u2014 may be static content", "rule_id": "SEC006", "scanner": "repobility-threat-engine", "confidence": 0.4, "correlation_key": "code|injection|token|328|sec006"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "packages/ui-tars/operators/browser-operator/src/ui-helper.ts"}, "region": {"startLine": 328}}}]}, {"ruleId": "SEC015", "level": "none", "message": {"text": "[SEC015] Insecure Randomness for Security (and 1 more): Same pattern found in 1 additional files. Review if needed."}, "properties": {"repobilityId": 10621, "scanner": "repobility-threat-engine", "fingerprint": "7b9ccdd419b3878e3d2ec8efb74d8ee23f94729fa3ed8ff97305e33614909ea3", "category": "crypto", "severity": "info", "confidence": 0.2, "triageState": "false_positive", "verdict": "likely_fp", "isResolved": true, "reason": "Deduplicated summary only: 1 additional occurrences found. The top occurrences remain visible as actionable findings.", "evidence": {"reason": "Deduplicated summary only: 1 additional occurrences found. The top occurrences remain visible as actionable findings.", "rule_id": "SEC015", "scanner": "repobility-threat-engine", "confidence": 0.2, "correlation_key": "fp|7b9ccdd419b3878e3d2ec8efb74d8ee23f94729fa3ed8ff97305e33614909ea3"}}}, {"ruleId": "SEC015", "level": "none", "message": {"text": "[SEC015] Insecure Randomness for Security: Weak PRNG used in security-sensitive context. Output is predictable."}, "properties": {"repobilityId": 10620, "scanner": "repobility-threat-engine", "fingerprint": "808384c74c9de8bd0faaa4e37f8f84fc87d2a1080c3cee0a755142498484519d", "category": "crypto", "severity": "info", "confidence": 0.15, "triageState": "false_positive", "verdict": "likely_fp", "isResolved": true, "reason": "Weak PRNG appears to be used for non-security behavior (UI, sampling, demos, shuffling, or backoff), not for secrets", "evidence": {"match": "Math.random()", "reason": "Weak PRNG appears to be used for non-security behavior (UI, sampling, demos, shuffling, or backoff), not for secrets", "rule_id": "SEC015", "scanner": "repobility-threat-engine", "confidence": 0.15, "correlation_key": "code|crypto|token|623|sec015"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/ui-tars/src/renderer/src/components/ui/sidebar.tsx"}, "region": {"startLine": 623}}}]}, {"ruleId": "SEC015", "level": "none", "message": {"text": "[SEC015] Insecure Randomness for Security: Weak PRNG used in security-sensitive context. Output is predictable."}, "properties": {"repobilityId": 10619, "scanner": "repobility-threat-engine", "fingerprint": "37b08a3ec34d18e6bbb93730bebb978d7ca7d26d63ce81f48ae6fe2e2cb67fda", "category": "crypto", "severity": "info", "confidence": 0.25, "triageState": "false_positive", "verdict": "likely_fp", "isResolved": true, "reason": "Weak PRNG appears to be used for non-security behavior (UI, sampling, demos, shuffling, or backoff), not for secrets", "evidence": {"match": "Math.random()", "reason": "Weak PRNG appears to be used for non-security behavior (UI, sampling, demos, shuffling, or backoff), not for secrets", "rule_id": "SEC015", "scanner": "repobility-threat-engine", "confidence": 0.25, "correlation_key": "code|crypto|token|86|sec015"}}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "multimodal/tarko/agent-server-next/src/services/sandbox/SandboxManager.ts"}, "region": {"startLine": 86}}}]}]}]}