{"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": "scanner-50b6bec74239252f", "name": "Stray `console.log` in TS/JS \u2014 latex-studio/apps/api/src/coderive/engine.ts:29", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 latex-studio/apps/api/src/coderive/engine.ts:29"}, "fullDescription": {"text": "Replace with the toast helper, an error boundary, or remove. `console.warn` / `console.error` are acceptable.\n\nWhy: Hygiene \u2014 easy to leak debug output.\nRule id: fq.console-leak"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-eb058a97dace0fc2", "name": "Stray `console.log` in TS/JS \u2014 latex-studio/apps/api/prisma/seed.ts:164", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 latex-studio/apps/api/prisma/seed.ts:164"}, "fullDescription": {"text": "Replace with the toast helper, an error boundary, or remove. `console.warn` / `console.error` are acceptable.\n\nWhy: Hygiene \u2014 easy to leak debug output.\nRule id: fq.console-leak"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-da0873bb6aac875d", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 latex-studio/apps/web/app/layout.tsx:36", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 latex-studio/apps/web/app/layout.tsx:36"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-361429c771c809cd", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/app/plugins/page.tsx:190", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/app/plugins/page.tsx:190"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-646d28d1aa7f9654", "name": "Icon-only button without accessible name \u2014 latex-studio/apps/web/app/files/page.tsx:565", "shortDescription": {"text": "Icon-only button without accessible name \u2014 latex-studio/apps/web/app/files/page.tsx:565"}, "fullDescription": {"text": "A `<button>` whose only child is a single glyph or symbol needs `title=` or `aria-label=` so screen readers (and tooltips on hover) work.\n\nWhy: P3 in CHECKLIST.md \u2014 icon-only buttons skipped a title.\nRule id: fq.button.no-label"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2deeeff9de22ae67", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/app/files/page.tsx:370", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/app/files/page.tsx:370"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-8bca86b3b22ae145", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/app/math-diagram/page.tsx:77", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/app/math-diagram/page.tsx:77"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-94af985afbd869da", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/AppNav.tsx:119", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/AppNav.tsx:119"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-94a8ada2b3d8da7d", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 latex-studio/apps/web/components/Landing.tsx:97", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 latex-studio/apps/web/components/Landing.tsx:97"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-9178dd3e7df9fa84", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/FileTree.tsx:257", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/FileTree.tsx:257"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-f42d959ac2106235", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/Toolbar.tsx:145", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/Toolbar.tsx:145"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-2e2a2808d3526bc4", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/RunPythonPicker.tsx:85", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/RunPythonPicker.tsx:85"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-3eff11dec5c20af9", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/EditorTabs.tsx:42", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/EditorTabs.tsx:42"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-5e56de720505d147", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/SnapshotsDialog.tsx:85", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/SnapshotsDialog.tsx:85"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-a0186e3ff894c510", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx:943", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx:943"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-acb1daf3d4379d7b", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/diagram/TemplatePalette.tsx:85", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/diagram/TemplatePalette.tsx:85"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-9fbd5ef73f7bf215", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/diagram/DiagramEditor.tsx:156", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/diagram/DiagramEditor.tsx:156"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-8d3f26c43c07dc74", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/coderive/CoderivePanel.tsx:96", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/coderive/CoderivePanel.tsx:96"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-4dc638b8e6c5bcb7", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/library/LibraryDialogs.tsx:25", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/library/LibraryDialogs.tsx:25"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-f3294a82087527c2", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/library/LibraryPanel.tsx:121", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/library/LibraryPanel.tsx:121"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-0b720f911c6292ed", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 latex-studio/apps/web/components/editor/VisualView.tsx:295", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 latex-studio/apps/web/components/editor/VisualView.tsx:295"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-4fe2ea0e91febc77", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/thesis/MathsAuditPanel.tsx:135", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/thesis/MathsAuditPanel.tsx:135"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-2e463aebb051fdcc", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/thesis/OutlinePanel.tsx:33", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/thesis/OutlinePanel.tsx:33"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-b1d1c5493b38b75c", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/projects/ProjectPalette.tsx:127", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/projects/ProjectPalette.tsx:127"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-cdc32664e062ec67", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/projects/ProjectFolderTree.tsx:77", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/projects/ProjectFolderTree.tsx:77"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-32fb4f2bff6a65a6", "name": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/ai/ChatSidebar.tsx:66", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/ai/ChatSidebar.tsx:66"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-ae1947f7253035d7", "name": "Dockerfile runs as root: latex-studio/apps/api/Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: latex-studio/apps/api/Dockerfile"}, "fullDescription": {"text": "No non-root USER set. Containers running as root expand the blast radius of any vulnerability inside the image."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-5530e805f9e4b853", "name": "Docker base image is tag-pinned but not digest-pinned: node:20-slim", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-slim"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-1cdf893395538f83", "name": "Dockerfile runs as root: latex-studio/services/mathcheck/Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: latex-studio/services/mathcheck/Dockerfile"}, "fullDescription": {"text": "No non-root USER set. Containers running as root expand the blast radius of any vulnerability inside the image."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-71169cde63546025", "name": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-fb911b49221e78d2", "name": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-be17a1f59d74b533", "name": "Insecure pattern 'node_child_process' in latex-studio/apps/api/src/compile/spawn.ts:1", "shortDescription": {"text": "Insecure pattern 'node_child_process' in latex-studio/apps/api/src/compile/spawn.ts:1"}, "fullDescription": {"text": "Found a known-risky pattern (node_child_process). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-86e9b259a95f3798", "name": "Insecure pattern 'node_child_process' in latex-studio/apps/api/src/providers/cli/spawnCli.ts:1", "shortDescription": {"text": "Insecure pattern 'node_child_process' in latex-studio/apps/api/src/providers/cli/spawnCli.ts:1"}, "fullDescription": {"text": "Found a known-risky pattern (node_child_process). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-c95dd4a2a26704f8", "name": "Insecure pattern 'node_child_process' in latex-studio/apps/api/src/run/spawn.ts:1", "shortDescription": {"text": "Insecure pattern 'node_child_process' in latex-studio/apps/api/src/run/spawn.ts:1"}, "fullDescription": {"text": "Found a known-risky pattern (node_child_process). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-2e2c7ccddd00e921", "name": "Insecure pattern 'node_child_process' in latex-studio/apps/api/src/routes/diagram.ts:2", "shortDescription": {"text": "Insecure pattern 'node_child_process' in latex-studio/apps/api/src/routes/diagram.ts:2"}, "fullDescription": {"text": "Found a known-risky pattern (node_child_process). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-76f21049054cda42", "name": "Insecure pattern 'dangerous_innerhtml' in latex-studio/apps/web/app/layout.tsx:36", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in latex-studio/apps/web/app/layout.tsx:36"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-0b60592559a2b485", "name": "Insecure pattern 'dangerous_innerhtml' in latex-studio/apps/web/components/Landing.tsx:97", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in latex-studio/apps/web/components/Landing.tsx:97"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-a05bc162eb94e8c3", "name": "Insecure pattern 'dangerous_innerhtml' in latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx:943", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx:943"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-2ce010cdbfc5ec6a", "name": "Insecure pattern 'dangerous_innerhtml' in latex-studio/apps/web/components/editor/VisualView.tsx:295", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in latex-studio/apps/web/components/editor/VisualView.tsx:295"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-8426302c3129ab32", "name": "Insecure pattern 'direct_innerhtml_assignment' in latex-studio/apps/web/components/editor/VisualView.tsx:194", "shortDescription": {"text": "Insecure pattern 'direct_innerhtml_assignment' in latex-studio/apps/web/components/editor/VisualView.tsx:194"}, "fullDescription": {"text": "Found a known-risky pattern (direct_innerhtml_assignment). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-1ba69f32cd7c1728", "name": "Possible secret in latex-studio/apps/web/lib/session.ts", "shortDescription": {"text": "Possible secret in latex-studio/apps/web/lib/session.ts"}, "fullDescription": {"text": "Detected pattern matching password_literal. Rotate the credential and move to a secret manager."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "critical", "confidence": 1.0}}, {"id": "scanner-4d62572f67dcfbb8", "name": "package.json defines install-time lifecycle scripts", "shortDescription": {"text": "package.json defines install-time lifecycle scripts"}, "fullDescription": {"text": "preinstall/install/postinstall/prepare scripts execute during dependency installation. Review them carefully for network calls, obfuscation, shell execution, or credential access."}, "properties": {"scanner": "scanner-primary", "layer": "cicd", "severity": "low", "confidence": 1.0}}, {"id": "scanner-e10e4f9e3045d8ec", "name": "Very large file: latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx (1642 lines)", "shortDescription": {"text": "Very large file: latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx (1642 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-753264f318d9bf79", "name": "Very large file: latex-studio/apps/web/lib/diagram/templates/catalog.tsx (1327 lines)", "shortDescription": {"text": "Very large file: latex-studio/apps/web/lib/diagram/templates/catalog.tsx (1327 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ea3b5e389d8c9c0f", "name": "Low test-to-source ratio", "shortDescription": {"text": "Low test-to-source ratio"}, "fullDescription": {"text": "60 tests / 261 src (ratio 0.23)."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-141b30a41e03817b", "name": "No license file detected", "shortDescription": {"text": "No license file detected"}, "fullDescription": {"text": "No LICENSE/COPYING/NOTICE file was found. Generated repositories often omit licensing, which blocks reuse and automated intake."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ec7b18aeb354fe61", "name": "Node manifest has dependencies but no lockfile: latex-studio/packages/shared/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: latex-studio/packages/shared/package.json"}, "fullDescription": {"text": "`package.json` declares dependencies, but no same-directory npm/pnpm/yarn/bun lockfile was found. Generated projects without lockfiles are less reproducible and harder to secure-scan precisely."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-728c88858584753c", "name": "Node manifest has dependencies but no lockfile: latex-studio/apps/api/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: latex-studio/apps/api/package.json"}, "fullDescription": {"text": "`package.json` declares dependencies, but no same-directory npm/pnpm/yarn/bun lockfile was found. Generated projects without lockfiles are less reproducible and harder to secure-scan precisely."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-d6d03695863def63", "name": "Node manifest has dependencies but no lockfile: latex-studio/apps/web/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: latex-studio/apps/web/package.json"}, "fullDescription": {"text": "`package.json` declares dependencies, but no same-directory npm/pnpm/yarn/bun lockfile was found. Generated projects without lockfiles are less reproducible and harder to secure-scan precisely."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-3ab5d313dda8e5f9", "name": "Debug logging residue appears in source files", "shortDescription": {"text": "Debug logging residue appears in source files"}, "fullDescription": {"text": "Found 12 console/debugger/print-style debug statements in non-test source. This is a common fast-generation residue before production cleanup."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-72b2a6250083a784", "name": "Placeholder or mock-heavy implementation detected", "shortDescription": {"text": "Placeholder or mock-heavy implementation detected"}, "fullDescription": {"text": "Found 59 placeholder/mock markers across 28 source files. This often means the repo looks complete while core flows still use generated scaffolding or fake data."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-2d0c7b7ab8f8aacf", "name": "Critical user flow still appears backed by mock or placeholder data", "shortDescription": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "fullDescription": {"text": "A payment/auth/admin/order/billing-style flow contains mock, fake, TODO, dummy, or placeholder markers in runtime source. In the Fable corpus this is a high-leverage completeness smell: the app can look finished while the money, identity, or tenant flow is still scaffolded."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-b9088664ace7f748", "name": "Composite production-readiness gap", "shortDescription": {"text": "Composite production-readiness gap"}, "fullDescription": {"text": "Multiple low-cost hardening controls are missing together: license, ci, lockfile. Opus verification showed these co-occurring gaps are a better readiness signal than reading each flag in isolation."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-931233f637da4b03", "name": "Commented-code block (5 lines) in latex-studio/packages/shared/src/index.ts:1103", "shortDescription": {"text": "Commented-code block (5 lines) in latex-studio/packages/shared/src/index.ts:1103"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-f1a2b17b53e63355", "name": "Commented-code block (6 lines) in latex-studio/apps/api/src/compile/service.ts:97", "shortDescription": {"text": "Commented-code block (6 lines) in latex-studio/apps/api/src/compile/service.ts:97"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-2c2bcc9c680e389f", "name": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/literature/sources/zotero.ts:36", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/literature/sources/zotero.ts:36"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-ad3838f915935b96", "name": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/literature/sources/semanticScholar.ts:34", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/literature/sources/semanticScholar.ts:34"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-07f1e5f462392041", "name": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/literature/sources/crossref.ts:25", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/literature/sources/crossref.ts:25"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-cc7531fbbf5b805e", "name": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/literature/sources/arxiv.ts:16", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/literature/sources/arxiv.ts:16"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-e8e6ced7dc68c0b8", "name": "Commented-code block (8 lines) in latex-studio/apps/api/src/coderive/document.ts:223", "shortDescription": {"text": "Commented-code block (8 lines) in latex-studio/apps/api/src/coderive/document.ts:223"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-967eb1b60c641b54", "name": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/prose/check.ts:107", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/prose/check.ts:107"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-cffc2a681bc7860c", "name": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/storage/sources/dropbox.ts:27", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/storage/sources/dropbox.ts:27"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-08073f8370c77caa", "name": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/storage/sources/googleDrive.ts:28", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/storage/sources/googleDrive.ts:28"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-a56f1759b4a481f5", "name": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/storage/sources/onedrive.ts:25", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/storage/sources/onedrive.ts:25"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-b1755af1d90825c9", "name": "Commented-code block (5 lines) in latex-studio/apps/api/src/routes/coderive.ts:56", "shortDescription": {"text": "Commented-code block (5 lines) in latex-studio/apps/api/src/routes/coderive.ts:56"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-492c2ac6624dbdb8", "name": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/routes/connectors.ts:248", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/routes/connectors.ts:248"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-fd814f5dbb5c5092", "name": "Commented-code block (6 lines) in latex-studio/apps/api/src/routes/review.ts:134", "shortDescription": {"text": "Commented-code block (6 lines) in latex-studio/apps/api/src/routes/review.ts:134"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-53a3f060a97e90ee", "name": "Commented-code block (6 lines) in latex-studio/apps/api/src/routes/diagram.ts:189", "shortDescription": {"text": "Commented-code block (6 lines) in latex-studio/apps/api/src/routes/diagram.ts:189"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-0fca7944078cd58a", "name": "Commented-code block (6 lines) in latex-studio/apps/api/src/routes/preview.ts:202", "shortDescription": {"text": "Commented-code block (6 lines) in latex-studio/apps/api/src/routes/preview.ts:202"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-45ef3be995c128bc", "name": "Commented-code block (5 lines) in latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx:517", "shortDescription": {"text": "Commented-code block (5 lines) in latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx:517"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-7adf34b82bc83084", "name": "Commented-code block (6 lines) in latex-studio/apps/web/components/editor/latexAutocomplete.ts:45", "shortDescription": {"text": "Commented-code block (6 lines) in latex-studio/apps/web/components/editor/latexAutocomplete.ts:45"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-d4617a441648fceb", "name": "Commented-code block (5 lines) in latex-studio/apps/web/components/editor/VisualView.tsx:107", "shortDescription": {"text": "Commented-code block (5 lines) in latex-studio/apps/web/components/editor/VisualView.tsx:107"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-396dfb9ac1d63d4c", "name": "Commented-code block (5 lines) in latex-studio/apps/web/lib/usage.ts:39", "shortDescription": {"text": "Commented-code block (5 lines) in latex-studio/apps/web/lib/usage.ts:39"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-b334d875f2339fa1", "name": "5 env vars used in code but missing from .env.example", "shortDescription": {"text": "5 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `ANTHROPIC_API_KEY`, `CI`, `CODERIVE_DEBUG`, `EMBED_MODEL`, `NEXT_DIST_DIR`. Add them (with a placeholder/comment) to .env.example so onboarding doesn't break."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-37383012f92e9a46", "name": "FastAPI POST `parse` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:40", "shortDescription": {"text": "FastAPI POST `parse` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:40"}, "fullDescription": {"text": "`@router.post` decorator with no `Depends(get_current_user)` or auth-shaped dependency in its signature. Mutating endpoints should require authentication unless explicitly public."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-7e384a5f0c818486", "name": "FastAPI POST `equivalent` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:66", "shortDescription": {"text": "FastAPI POST `equivalent` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:66"}, "fullDescription": {"text": "`@router.post` decorator with no `Depends(get_current_user)` or auth-shaped dependency in its signature. Mutating endpoints should require authentication unless explicitly public."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-99a1b9ecaaae00bf", "name": "FastAPI POST `check_derivation_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:87", "shortDescription": {"text": "FastAPI POST `check_derivation_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:87"}, "fullDescription": {"text": "`@router.post` decorator with no `Depends(get_current_user)` or auth-shaped dependency in its signature. Mutating endpoints should require authentication unless explicitly public."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-7228dff81e3b72e7", "name": "FastAPI POST `annotate_pdf_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:105", "shortDescription": {"text": "FastAPI POST `annotate_pdf_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:105"}, "fullDescription": {"text": "`@router.post` decorator with no `Depends(get_current_user)` or auth-shaped dependency in its signature. Mutating endpoints should require authentication unless explicitly public."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-90b4a3a9a1e5fee3", "name": "FastAPI POST `extract_pdf_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:119", "shortDescription": {"text": "FastAPI POST `extract_pdf_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:119"}, "fullDescription": {"text": "`@router.post` decorator with no `Depends(get_current_user)` or auth-shaped dependency in its signature. Mutating endpoints should require authentication unless explicitly public."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-994c67dfcd14b127", "name": "FastAPI POST `pdf_png_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:135", "shortDescription": {"text": "FastAPI POST `pdf_png_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:135"}, "fullDescription": {"text": "`@router.post` decorator with no `Depends(get_current_user)` or auth-shaped dependency in its signature. Mutating endpoints should require authentication unless explicitly public."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-f15b00275a4e3ea3", "name": "FastAPI POST `embed_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:163", "shortDescription": {"text": "FastAPI POST `embed_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:163"}, "fullDescription": {"text": "`@router.post` decorator with no `Depends(get_current_user)` or auth-shaped dependency in its signature. Mutating endpoints should require authentication unless explicitly public."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-c3c95fe32f326f1d", "name": "Dangling fetch: GET https://api.crossref.org/works/${encodeURIComponent(doi)} (latex-studio/apps/api/src/literature/stor", "shortDescription": {"text": "Dangling fetch: GET https://api.crossref.org/works/${encodeURIComponent(doi)} (latex-studio/apps/api/src/literature/storage.ts:67)"}, "fullDescription": {"text": "`latex-studio/apps/api/src/literature/storage.ts:67` calls `GET https://api.crossref.org/works/${encodeURIComponent(doi)}` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/api.crossref.org/works/<p>`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-4c78f8c11eeae1ca", "name": "Dangling fetch: GET https://arxiv.org/pdf/${normalizeId(id)}.pdf (latex-studio/apps/api/src/literature/sources/arxiv.ts:", "shortDescription": {"text": "Dangling fetch: GET https://arxiv.org/pdf/${normalizeId(id)}.pdf (latex-studio/apps/api/src/literature/sources/arxiv.ts:48)"}, "fullDescription": {"text": "`latex-studio/apps/api/src/literature/sources/arxiv.ts:48` calls `GET https://arxiv.org/pdf/${normalizeId(id)}.pdf` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/arxiv.org/pdf/<p>.pdf`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-c619062d5f09f4f0", "name": "Dangling fetch: GET https://www.googleapis.com/oauth2/v2/userinfo (latex-studio/apps/api/src/routes/connectors.ts:248)", "shortDescription": {"text": "Dangling fetch: GET https://www.googleapis.com/oauth2/v2/userinfo (latex-studio/apps/api/src/routes/connectors.ts:248)"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/connectors.ts:248` calls `GET https://www.googleapis.com/oauth2/v2/userinfo` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/www.googleapis.com/oauth2/v2/userinfo`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-a48d897323b61148", "name": "Dangling fetch: GET https://doi.org/${encodeURIComponent(doi.trim())} (latex-studio/apps/web/app/plugins/page.tsx:345)", "shortDescription": {"text": "Dangling fetch: GET https://doi.org/${encodeURIComponent(doi.trim())} (latex-studio/apps/web/app/plugins/page.tsx:345)"}, "fullDescription": {"text": "`latex-studio/apps/web/app/plugins/page.tsx:345` calls `GET https://doi.org/${encodeURIComponent(doi.trim())}` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/doi.org/<p>`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-198447cd66ac75ad", "name": "Dangling fetch: GET http://127.0.0.1:23119/connector/ping (latex-studio/apps/web/app/plugins/page.tsx:358)", "shortDescription": {"text": "Dangling fetch: GET http://127.0.0.1:23119/connector/ping (latex-studio/apps/web/app/plugins/page.tsx:358)"}, "fullDescription": {"text": "`latex-studio/apps/web/app/plugins/page.tsx:358` calls `GET http://127.0.0.1:23119/connector/ping` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/http:/127.0.0.1:23119/connector/ping`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-7eefc6e9dd65729c", "name": "Dangling fetch: GET /api${path} (latex-studio/apps/web/lib/api.ts:113)", "shortDescription": {"text": "Dangling fetch: GET /api${path} (latex-studio/apps/web/lib/api.ts:113)"}, "fullDescription": {"text": "`latex-studio/apps/web/lib/api.ts:113` calls `GET /api${path}` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/api/<p>`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-f02c6805954a6b7a", "name": "Dangling fetch: POST /api/projects/${projectId}/complete (latex-studio/apps/web/lib/api.ts:549)", "shortDescription": {"text": "Dangling fetch: POST /api/projects/${projectId}/complete (latex-studio/apps/web/lib/api.ts:549)"}, "fullDescription": {"text": "`latex-studio/apps/web/lib/api.ts:549` calls `POST /api/projects/${projectId}/complete` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/projects/<p>/complete`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-21d4e3431aa9b5dc", "name": "Unused endpoint: POST /parse", "shortDescription": {"text": "Unused endpoint: POST /parse"}, "fullDescription": {"text": "`latex-studio/services/mathcheck/app/main.py` declares `POST /parse` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-4205e3b2c27f79a9", "name": "Unused endpoint: POST /equivalent", "shortDescription": {"text": "Unused endpoint: POST /equivalent"}, "fullDescription": {"text": "`latex-studio/services/mathcheck/app/main.py` declares `POST /equivalent` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-7288092d3c36d67d", "name": "Unused endpoint: POST /check-derivation", "shortDescription": {"text": "Unused endpoint: POST /check-derivation"}, "fullDescription": {"text": "`latex-studio/services/mathcheck/app/main.py` declares `POST /check-derivation` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2f93237057dc469d", "name": "Unused endpoint: POST /annotate-pdf", "shortDescription": {"text": "Unused endpoint: POST /annotate-pdf"}, "fullDescription": {"text": "`latex-studio/services/mathcheck/app/main.py` declares `POST /annotate-pdf` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-237db72f32dfc964", "name": "Unused endpoint: POST /extract-pdf", "shortDescription": {"text": "Unused endpoint: POST /extract-pdf"}, "fullDescription": {"text": "`latex-studio/services/mathcheck/app/main.py` declares `POST /extract-pdf` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-aa6a6c8c87943670", "name": "Unused endpoint: POST /pdf-png", "shortDescription": {"text": "Unused endpoint: POST /pdf-png"}, "fullDescription": {"text": "`latex-studio/services/mathcheck/app/main.py` declares `POST /pdf-png` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-a05ffae6d751f4d0", "name": "Unused endpoint: POST /embed", "shortDescription": {"text": "Unused endpoint: POST /embed"}, "fullDescription": {"text": "`latex-studio/services/mathcheck/app/main.py` declares `POST /embed` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-a38795da6b632510", "name": "Unused endpoint: GET /embed/health", "shortDescription": {"text": "Unused endpoint: GET /embed/health"}, "fullDescription": {"text": "`latex-studio/services/mathcheck/app/main.py` declares `GET /embed/health` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6584ed1945ab2f58", "name": "Unused endpoint: POST /synctex/forward", "shortDescription": {"text": "Unused endpoint: POST /synctex/forward"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/compile.ts` declares `POST /synctex/forward` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-7b5457cae4ea02e1", "name": "Unused endpoint: POST /synctex/inverse", "shortDescription": {"text": "Unused endpoint: POST /synctex/inverse"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/compile.ts` declares `POST /synctex/inverse` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-c1e1ee09590b0a49", "name": "Unused endpoint: GET /projects", "shortDescription": {"text": "Unused endpoint: GET /projects"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/projects.ts` declares `GET /projects` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-58666816ba500374", "name": "Unused endpoint: POST /projects", "shortDescription": {"text": "Unused endpoint: POST /projects"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/projects.ts` declares `POST /projects` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-347909e2d1122e49", "name": "Unused endpoint: GET /project-folders", "shortDescription": {"text": "Unused endpoint: GET /project-folders"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/projectFolders.ts` declares `GET /project-folders` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-94c6aa8a0670bb1e", "name": "Unused endpoint: POST /project-folders", "shortDescription": {"text": "Unused endpoint: POST /project-folders"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/projectFolders.ts` declares `POST /project-folders` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-9fc02abe3073f5d2", "name": "Unused endpoint: GET /project-trash", "shortDescription": {"text": "Unused endpoint: GET /project-trash"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/projectFolders.ts` declares `GET /project-trash` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-917af810397c2314", "name": "Unused endpoint: DELETE /project-trash", "shortDescription": {"text": "Unused endpoint: DELETE /project-trash"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/projectFolders.ts` declares `DELETE /project-trash` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ef7f5df555c4d289", "name": "Unused endpoint: GET /connectors", "shortDescription": {"text": "Unused endpoint: GET /connectors"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/connectors.ts` declares `GET /connectors` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-1279ea9c133c498c", "name": "Unused endpoint: GET /ai/status", "shortDescription": {"text": "Unused endpoint: GET /ai/status"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/ai.ts` declares `GET /ai/status` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-87a6358bb2c65470", "name": "Unused endpoint: GET /ai/models", "shortDescription": {"text": "Unused endpoint: GET /ai/models"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/ai.ts` declares `GET /ai/models` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-945bf36870cb3302", "name": "Unused endpoint: GET /ai/stats", "shortDescription": {"text": "Unused endpoint: GET /ai/stats"}, "fullDescription": {"text": "`latex-studio/apps/api/src/routes/ai.ts` declares `GET /ai/stats` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}]}}, "automationDetails": {"id": "repobility/24767"}, "properties": {"repository": "bwalpole2025/L_Research", "repoUrl": "https://github.com/bwalpole2025/L_Research", "branch": "main"}, "results": [{"ruleId": "scanner-50b6bec74239252f", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 latex-studio/apps/api/src/coderive/engine.ts:29"}, "properties": {"repobilityId": "5645d53e94d14935", "scanner": "scanner-primary", "fingerprint": "50b6bec74239252f", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-eb058a97dace0fc2", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 latex-studio/apps/api/prisma/seed.ts:164"}, "properties": {"repobilityId": "7dc68e80a3700071", "scanner": "scanner-primary", "fingerprint": "eb058a97dace0fc2", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-da0873bb6aac875d", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 latex-studio/apps/web/app/layout.tsx:36"}, "properties": {"repobilityId": "96f615d6d4c0acac", "scanner": "scanner-primary", "fingerprint": "da0873bb6aac875d", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-361429c771c809cd", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/app/plugins/page.tsx:190"}, "properties": {"repobilityId": "670750e5c394c87e", "scanner": "scanner-primary", "fingerprint": "361429c771c809cd", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-646d28d1aa7f9654", "level": "note", "message": {"text": "Icon-only button without accessible name \u2014 latex-studio/apps/web/app/files/page.tsx:565"}, "properties": {"repobilityId": "b608ef335a88d08b", "scanner": "scanner-primary", "fingerprint": "646d28d1aa7f9654", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.button.no-label"]}}, {"ruleId": "scanner-2deeeff9de22ae67", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/app/files/page.tsx:370"}, "properties": {"repobilityId": "30f7c8399fb4f7e7", "scanner": "scanner-primary", "fingerprint": "2deeeff9de22ae67", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-8bca86b3b22ae145", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/app/math-diagram/page.tsx:77"}, "properties": {"repobilityId": "1d09615eac7d6307", "scanner": "scanner-primary", "fingerprint": "8bca86b3b22ae145", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-94af985afbd869da", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/AppNav.tsx:119"}, "properties": {"repobilityId": "66af705d4bd095a4", "scanner": "scanner-primary", "fingerprint": "94af985afbd869da", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-94a8ada2b3d8da7d", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 latex-studio/apps/web/components/Landing.tsx:97"}, "properties": {"repobilityId": "45c05cffa81868f1", "scanner": "scanner-primary", "fingerprint": "94a8ada2b3d8da7d", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-9178dd3e7df9fa84", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/FileTree.tsx:257"}, "properties": {"repobilityId": "56d90b0958606462", "scanner": "scanner-primary", "fingerprint": "9178dd3e7df9fa84", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f42d959ac2106235", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/Toolbar.tsx:145"}, "properties": {"repobilityId": "29db4cabee450a47", "scanner": "scanner-primary", "fingerprint": "f42d959ac2106235", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-2e2a2808d3526bc4", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/RunPythonPicker.tsx:85"}, "properties": {"repobilityId": "5d532253f1f004f0", "scanner": "scanner-primary", "fingerprint": "2e2a2808d3526bc4", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-3eff11dec5c20af9", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/EditorTabs.tsx:42"}, "properties": {"repobilityId": "db1e41f9c08dc023", "scanner": "scanner-primary", "fingerprint": "3eff11dec5c20af9", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-5e56de720505d147", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/SnapshotsDialog.tsx:85"}, "properties": {"repobilityId": "ac03917aff3e5343", "scanner": "scanner-primary", "fingerprint": "5e56de720505d147", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a0186e3ff894c510", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx:943"}, "properties": {"repobilityId": "a367983bbc9da281", "scanner": "scanner-primary", "fingerprint": "a0186e3ff894c510", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-acb1daf3d4379d7b", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/diagram/TemplatePalette.tsx:85"}, "properties": {"repobilityId": "b1953f69769dbbaf", "scanner": "scanner-primary", "fingerprint": "acb1daf3d4379d7b", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-9fbd5ef73f7bf215", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/diagram/DiagramEditor.tsx:156"}, "properties": {"repobilityId": "36e9ec9638c62c78", "scanner": "scanner-primary", "fingerprint": "9fbd5ef73f7bf215", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-8d3f26c43c07dc74", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/coderive/CoderivePanel.tsx:96"}, "properties": {"repobilityId": "573c361bc7bd4aa2", "scanner": "scanner-primary", "fingerprint": "8d3f26c43c07dc74", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-4dc638b8e6c5bcb7", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/library/LibraryDialogs.tsx:25"}, "properties": {"repobilityId": "9eb371bde2c2cf8a", "scanner": "scanner-primary", "fingerprint": "4dc638b8e6c5bcb7", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f3294a82087527c2", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/library/LibraryPanel.tsx:121"}, "properties": {"repobilityId": "ff46e408f8601cc2", "scanner": "scanner-primary", "fingerprint": "f3294a82087527c2", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-0b720f911c6292ed", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 latex-studio/apps/web/components/editor/VisualView.tsx:295"}, "properties": {"repobilityId": "313e933bba1b1603", "scanner": "scanner-primary", "fingerprint": "0b720f911c6292ed", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-4fe2ea0e91febc77", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/thesis/MathsAuditPanel.tsx:135"}, "properties": {"repobilityId": "17add1618e5158ca", "scanner": "scanner-primary", "fingerprint": "4fe2ea0e91febc77", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-2e463aebb051fdcc", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/thesis/OutlinePanel.tsx:33"}, "properties": {"repobilityId": "12057c54a0a811b2", "scanner": "scanner-primary", "fingerprint": "2e463aebb051fdcc", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-b1d1c5493b38b75c", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/projects/ProjectPalette.tsx:127"}, "properties": {"repobilityId": "bf539cb3beadb3b5", "scanner": "scanner-primary", "fingerprint": "b1d1c5493b38b75c", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-cdc32664e062ec67", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/projects/ProjectFolderTree.tsx:77"}, "properties": {"repobilityId": "a2cf5550e0f3b65a", "scanner": "scanner-primary", "fingerprint": "cdc32664e062ec67", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-32fb4f2bff6a65a6", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 latex-studio/apps/web/components/ai/ChatSidebar.tsx:66"}, "properties": {"repobilityId": "d05079ee4932f713", "scanner": "scanner-primary", "fingerprint": "32fb4f2bff6a65a6", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-ae1947f7253035d7", "level": "warning", "message": {"text": "Dockerfile runs as root: latex-studio/apps/api/Dockerfile"}, "properties": {"repobilityId": "fe6129f8735ad158", "scanner": "scanner-primary", "fingerprint": "ae1947f7253035d7", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-5530e805f9e4b853", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-slim"}, "properties": {"repobilityId": "d78ce3f7c72b148f", "scanner": "scanner-primary", "fingerprint": "5530e805f9e4b853", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/api/Dockerfile"}, "region": {"startLine": 3}}}]}, {"ruleId": "scanner-1cdf893395538f83", "level": "warning", "message": {"text": "Dockerfile runs as root: latex-studio/services/mathcheck/Dockerfile"}, "properties": {"repobilityId": "394374f060d95982", "scanner": "scanner-primary", "fingerprint": "1cdf893395538f83", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-71169cde63546025", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim"}, "properties": {"repobilityId": "8d953c167d5bb46d", "scanner": "scanner-primary", "fingerprint": "71169cde63546025", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/services/mathcheck/Dockerfile"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-fb911b49221e78d2", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim"}, "properties": {"repobilityId": "3ee057ec24e6844f", "scanner": "scanner-primary", "fingerprint": "fb911b49221e78d2", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/services/pyrun/Dockerfile"}, "region": {"startLine": 5}}}]}, {"ruleId": "scanner-be17a1f59d74b533", "level": "warning", "message": {"text": "Insecure pattern 'node_child_process' in latex-studio/apps/api/src/compile/spawn.ts:1"}, "properties": {"repobilityId": "fa220397324bfd49", "scanner": "scanner-primary", "fingerprint": "be17a1f59d74b533", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "node_child_process"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/api/src/compile/spawn.ts"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-86e9b259a95f3798", "level": "warning", "message": {"text": "Insecure pattern 'node_child_process' in latex-studio/apps/api/src/providers/cli/spawnCli.ts:1"}, "properties": {"repobilityId": "e3d60c962001a06b", "scanner": "scanner-primary", "fingerprint": "86e9b259a95f3798", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "node_child_process"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/api/src/providers/cli/spawnCli.ts"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-c95dd4a2a26704f8", "level": "warning", "message": {"text": "Insecure pattern 'node_child_process' in latex-studio/apps/api/src/run/spawn.ts:1"}, "properties": {"repobilityId": "ca25c231e60fa9da", "scanner": "scanner-primary", "fingerprint": "c95dd4a2a26704f8", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "node_child_process"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/api/src/run/spawn.ts"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-2e2c7ccddd00e921", "level": "warning", "message": {"text": "Insecure pattern 'node_child_process' in latex-studio/apps/api/src/routes/diagram.ts:2"}, "properties": {"repobilityId": "57ed6e0bf2e48fe3", "scanner": "scanner-primary", "fingerprint": "2e2c7ccddd00e921", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "node_child_process"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/api/src/routes/diagram.ts"}, "region": {"startLine": 2}}}]}, {"ruleId": "scanner-76f21049054cda42", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in latex-studio/apps/web/app/layout.tsx:36"}, "properties": {"repobilityId": "9799497c0f7d41fb", "scanner": "scanner-primary", "fingerprint": "76f21049054cda42", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/web/app/layout.tsx"}, "region": {"startLine": 36}}}]}, {"ruleId": "scanner-0b60592559a2b485", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in latex-studio/apps/web/components/Landing.tsx:97"}, "properties": {"repobilityId": "5d102d57f68ba364", "scanner": "scanner-primary", "fingerprint": "0b60592559a2b485", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/web/components/Landing.tsx"}, "region": {"startLine": 97}}}]}, {"ruleId": "scanner-a05bc162eb94e8c3", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx:943"}, "properties": {"repobilityId": "7e8d7725c1dda80d", "scanner": "scanner-primary", "fingerprint": "a05bc162eb94e8c3", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx"}, "region": {"startLine": 943}}}]}, {"ruleId": "scanner-2ce010cdbfc5ec6a", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in latex-studio/apps/web/components/editor/VisualView.tsx:295"}, "properties": {"repobilityId": "d5f42cfb0d419999", "scanner": "scanner-primary", "fingerprint": "2ce010cdbfc5ec6a", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/web/components/editor/VisualView.tsx"}, "region": {"startLine": 295}}}]}, {"ruleId": "scanner-8426302c3129ab32", "level": "warning", "message": {"text": "Insecure pattern 'direct_innerhtml_assignment' in latex-studio/apps/web/components/editor/VisualView.tsx:194"}, "properties": {"repobilityId": "822ad8a5337d697c", "scanner": "scanner-primary", "fingerprint": "8426302c3129ab32", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "direct_innerhtml_assignment"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/web/components/editor/VisualView.tsx"}, "region": {"startLine": 194}}}]}, {"ruleId": "scanner-1ba69f32cd7c1728", "level": "error", "message": {"text": "Possible secret in latex-studio/apps/web/lib/session.ts"}, "properties": {"repobilityId": "c834d85c141a5fbd", "scanner": "scanner-primary", "fingerprint": "1ba69f32cd7c1728", "layer": "security", "severity": "critical", "confidence": 1.0, "tags": ["secrets"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/web/lib/session.ts"}, "region": {"startLine": 17}}}]}, {"ruleId": "scanner-4d62572f67dcfbb8", "level": "note", "message": {"text": "package.json defines install-time lifecycle scripts"}, "properties": {"repobilityId": "7e70959244ccc8dc", "scanner": "scanner-primary", "fingerprint": "4d62572f67dcfbb8", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "npm", "install-scripts"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/api/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-e10e4f9e3045d8ec", "level": "note", "message": {"text": "Very large file: latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx (1642 lines)"}, "properties": {"repobilityId": "af8c75755a9061f4", "scanner": "scanner-primary", "fingerprint": "e10e4f9e3045d8ec", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-753264f318d9bf79", "level": "note", "message": {"text": "Very large file: latex-studio/apps/web/lib/diagram/templates/catalog.tsx (1327 lines)"}, "properties": {"repobilityId": "81b3fc77321ccaf6", "scanner": "scanner-primary", "fingerprint": "753264f318d9bf79", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-ea3b5e389d8c9c0f", "level": "note", "message": {"text": "Low test-to-source ratio"}, "properties": {"repobilityId": "ef7b2552cc00a375", "scanner": "scanner-primary", "fingerprint": "ea3b5e389d8c9c0f", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["tests"]}}, {"ruleId": "scanner-141b30a41e03817b", "level": "note", "message": {"text": "No license file detected"}, "properties": {"repobilityId": "8d10c379f96471ee", "scanner": "scanner-primary", "fingerprint": "141b30a41e03817b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["license", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-ec7b18aeb354fe61", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: latex-studio/packages/shared/package.json"}, "properties": {"repobilityId": "481ce1e0fb959ad5", "scanner": "scanner-primary", "fingerprint": "ec7b18aeb354fe61", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/packages/shared/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-728c88858584753c", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: latex-studio/apps/api/package.json"}, "properties": {"repobilityId": "0196908a0419b7e3", "scanner": "scanner-primary", "fingerprint": "728c88858584753c", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/api/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-d6d03695863def63", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: latex-studio/apps/web/package.json"}, "properties": {"repobilityId": "740055bb1c3a0f7b", "scanner": "scanner-primary", "fingerprint": "d6d03695863def63", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/apps/web/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-3ab5d313dda8e5f9", "level": "note", "message": {"text": "Debug logging residue appears in source files"}, "properties": {"repobilityId": "916c85005f65ed67", "scanner": "scanner-primary", "fingerprint": "3ab5d313dda8e5f9", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["debug", "cleanup", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-72b2a6250083a784", "level": "warning", "message": {"text": "Placeholder or mock-heavy implementation detected"}, "properties": {"repobilityId": "0ec51ceea700614a", "scanner": "scanner-primary", "fingerprint": "72b2a6250083a784", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "incomplete", "generated-repo-pattern"]}}, {"ruleId": "scanner-2d0c7b7ab8f8aacf", "level": "warning", "message": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "properties": {"repobilityId": "bb52dc790a13bfbc", "scanner": "scanner-primary", "fingerprint": "2d0c7b7ab8f8aacf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "critical-flow", "generated-repo-pattern"]}}, {"ruleId": "scanner-b9088664ace7f748", "level": "warning", "message": {"text": "Composite production-readiness gap"}, "properties": {"repobilityId": "b8d5fec8118264fc", "scanner": "scanner-primary", "fingerprint": "b9088664ace7f748", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["production-readiness", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-931233f637da4b03", "level": "none", "message": {"text": "Commented-code block (5 lines) in latex-studio/packages/shared/src/index.ts:1103"}, "properties": {"repobilityId": "3881afa8f06e248d", "scanner": "scanner-primary", "fingerprint": "931233f637da4b03", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-f1a2b17b53e63355", "level": "none", "message": {"text": "Commented-code block (6 lines) in latex-studio/apps/api/src/compile/service.ts:97"}, "properties": {"repobilityId": "674a0d816ebbb68a", "scanner": "scanner-primary", "fingerprint": "f1a2b17b53e63355", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-2c2bcc9c680e389f", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/literature/sources/zotero.ts:36"}, "properties": {"repobilityId": "c4a1648a1ff9a834", "scanner": "scanner-primary", "fingerprint": "2c2bcc9c680e389f", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-ad3838f915935b96", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/literature/sources/semanticScholar.ts:34"}, "properties": {"repobilityId": "e0e049a588cfd4d1", "scanner": "scanner-primary", "fingerprint": "ad3838f915935b96", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-07f1e5f462392041", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/literature/sources/crossref.ts:25"}, "properties": {"repobilityId": "144d914b655f60fe", "scanner": "scanner-primary", "fingerprint": "07f1e5f462392041", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-cc7531fbbf5b805e", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/literature/sources/arxiv.ts:16"}, "properties": {"repobilityId": "6a7278fa17f24545", "scanner": "scanner-primary", "fingerprint": "cc7531fbbf5b805e", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-e8e6ced7dc68c0b8", "level": "none", "message": {"text": "Commented-code block (8 lines) in latex-studio/apps/api/src/coderive/document.ts:223"}, "properties": {"repobilityId": "e93a41cdec0a7a52", "scanner": "scanner-primary", "fingerprint": "e8e6ced7dc68c0b8", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-967eb1b60c641b54", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/prose/check.ts:107"}, "properties": {"repobilityId": "b1edfd22491cb7db", "scanner": "scanner-primary", "fingerprint": "967eb1b60c641b54", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-cffc2a681bc7860c", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/storage/sources/dropbox.ts:27"}, "properties": {"repobilityId": "d9f663be23430857", "scanner": "scanner-primary", "fingerprint": "cffc2a681bc7860c", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-08073f8370c77caa", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/storage/sources/googleDrive.ts:28"}, "properties": {"repobilityId": "e7374cccd8c749a1", "scanner": "scanner-primary", "fingerprint": "08073f8370c77caa", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-a56f1759b4a481f5", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/storage/sources/onedrive.ts:25"}, "properties": {"repobilityId": "6513475a9d2dc7a8", "scanner": "scanner-primary", "fingerprint": "a56f1759b4a481f5", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-b1755af1d90825c9", "level": "none", "message": {"text": "Commented-code block (5 lines) in latex-studio/apps/api/src/routes/coderive.ts:56"}, "properties": {"repobilityId": "aabc857455a0e776", "scanner": "scanner-primary", "fingerprint": "b1755af1d90825c9", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-492c2ac6624dbdb8", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 latex-studio/apps/api/src/routes/connectors.ts:248"}, "properties": {"repobilityId": "5a7c23af39d70a5b", "scanner": "scanner-primary", "fingerprint": "492c2ac6624dbdb8", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-fd814f5dbb5c5092", "level": "none", "message": {"text": "Commented-code block (6 lines) in latex-studio/apps/api/src/routes/review.ts:134"}, "properties": {"repobilityId": "fd68253113c83764", "scanner": "scanner-primary", "fingerprint": "fd814f5dbb5c5092", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-53a3f060a97e90ee", "level": "none", "message": {"text": "Commented-code block (6 lines) in latex-studio/apps/api/src/routes/diagram.ts:189"}, "properties": {"repobilityId": "a9bc89e070279d2f", "scanner": "scanner-primary", "fingerprint": "53a3f060a97e90ee", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-0fca7944078cd58a", "level": "none", "message": {"text": "Commented-code block (6 lines) in latex-studio/apps/api/src/routes/preview.ts:202"}, "properties": {"repobilityId": "945ec17b0d7f44f9", "scanner": "scanner-primary", "fingerprint": "0fca7944078cd58a", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-45ef3be995c128bc", "level": "none", "message": {"text": "Commented-code block (5 lines) in latex-studio/apps/web/components/diagram/TikzDiagramEditor.tsx:517"}, "properties": {"repobilityId": "df86c178b0db7248", "scanner": "scanner-primary", "fingerprint": "45ef3be995c128bc", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-7adf34b82bc83084", "level": "none", "message": {"text": "Commented-code block (6 lines) in latex-studio/apps/web/components/editor/latexAutocomplete.ts:45"}, "properties": {"repobilityId": "e52e42074076160e", "scanner": "scanner-primary", "fingerprint": "7adf34b82bc83084", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-d4617a441648fceb", "level": "none", "message": {"text": "Commented-code block (5 lines) in latex-studio/apps/web/components/editor/VisualView.tsx:107"}, "properties": {"repobilityId": "43592da83d84f2cf", "scanner": "scanner-primary", "fingerprint": "d4617a441648fceb", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-396dfb9ac1d63d4c", "level": "none", "message": {"text": "Commented-code block (5 lines) in latex-studio/apps/web/lib/usage.ts:39"}, "properties": {"repobilityId": "0ee6c4b45a75d8d7", "scanner": "scanner-primary", "fingerprint": "396dfb9ac1d63d4c", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-b334d875f2339fa1", "level": "note", "message": {"text": "5 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "faa38682016f5d53", "scanner": "scanner-primary", "fingerprint": "b334d875f2339fa1", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "config-drift"]}}, {"ruleId": "scanner-37383012f92e9a46", "level": "error", "message": {"text": "FastAPI POST `parse` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:40"}, "properties": {"repobilityId": "36a469120ddc4e79", "scanner": "scanner-primary", "fingerprint": "37383012f92e9a46", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/services/mathcheck/app/main.py"}, "region": {"startLine": 40}}}]}, {"ruleId": "scanner-7e384a5f0c818486", "level": "error", "message": {"text": "FastAPI POST `equivalent` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:66"}, "properties": {"repobilityId": "dfc8be86e41561e9", "scanner": "scanner-primary", "fingerprint": "7e384a5f0c818486", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/services/mathcheck/app/main.py"}, "region": {"startLine": 66}}}]}, {"ruleId": "scanner-99a1b9ecaaae00bf", "level": "error", "message": {"text": "FastAPI POST `check_derivation_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:87"}, "properties": {"repobilityId": "37c9b32a2af591ec", "scanner": "scanner-primary", "fingerprint": "99a1b9ecaaae00bf", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/services/mathcheck/app/main.py"}, "region": {"startLine": 87}}}]}, {"ruleId": "scanner-7228dff81e3b72e7", "level": "error", "message": {"text": "FastAPI POST `annotate_pdf_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:105"}, "properties": {"repobilityId": "c30447247da0ef06", "scanner": "scanner-primary", "fingerprint": "7228dff81e3b72e7", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/services/mathcheck/app/main.py"}, "region": {"startLine": 105}}}]}, {"ruleId": "scanner-90b4a3a9a1e5fee3", "level": "error", "message": {"text": "FastAPI POST `extract_pdf_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:119"}, "properties": {"repobilityId": "da96e616fd25e72c", "scanner": "scanner-primary", "fingerprint": "90b4a3a9a1e5fee3", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/services/mathcheck/app/main.py"}, "region": {"startLine": 119}}}]}, {"ruleId": "scanner-994c67dfcd14b127", "level": "error", "message": {"text": "FastAPI POST `pdf_png_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:135"}, "properties": {"repobilityId": "c7529d77d10a7ffc", "scanner": "scanner-primary", "fingerprint": "994c67dfcd14b127", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/services/mathcheck/app/main.py"}, "region": {"startLine": 135}}}]}, {"ruleId": "scanner-f15b00275a4e3ea3", "level": "error", "message": {"text": "FastAPI POST `embed_endpoint` without auth dependency \u2014 latex-studio/services/mathcheck/app/main.py:163"}, "properties": {"repobilityId": "37af2f6a9cead0aa", "scanner": "scanner-primary", "fingerprint": "f15b00275a4e3ea3", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "latex-studio/services/mathcheck/app/main.py"}, "region": {"startLine": 163}}}]}, {"ruleId": "scanner-c3c95fe32f326f1d", "level": "error", "message": {"text": "Dangling fetch: GET https://api.crossref.org/works/${encodeURIComponent(doi)} (latex-studio/apps/api/src/literature/storage.ts:67)"}, "properties": {"repobilityId": "d842b0f00e15a44a", "scanner": "scanner-primary", "fingerprint": "c3c95fe32f326f1d", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-4c78f8c11eeae1ca", "level": "error", "message": {"text": "Dangling fetch: GET https://arxiv.org/pdf/${normalizeId(id)}.pdf (latex-studio/apps/api/src/literature/sources/arxiv.ts:48)"}, "properties": {"repobilityId": "db95ec72b13a059e", "scanner": "scanner-primary", "fingerprint": "4c78f8c11eeae1ca", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-c619062d5f09f4f0", "level": "error", "message": {"text": "Dangling fetch: GET https://www.googleapis.com/oauth2/v2/userinfo (latex-studio/apps/api/src/routes/connectors.ts:248)"}, "properties": {"repobilityId": "7c46335d401e135f", "scanner": "scanner-primary", "fingerprint": "c619062d5f09f4f0", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-a48d897323b61148", "level": "error", "message": {"text": "Dangling fetch: GET https://doi.org/${encodeURIComponent(doi.trim())} (latex-studio/apps/web/app/plugins/page.tsx:345)"}, "properties": {"repobilityId": "70ce882c51e3a715", "scanner": "scanner-primary", "fingerprint": "a48d897323b61148", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-198447cd66ac75ad", "level": "error", "message": {"text": "Dangling fetch: GET http://127.0.0.1:23119/connector/ping (latex-studio/apps/web/app/plugins/page.tsx:358)"}, "properties": {"repobilityId": "68e5d63a016b0bac", "scanner": "scanner-primary", "fingerprint": "198447cd66ac75ad", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-7eefc6e9dd65729c", "level": "error", "message": {"text": "Dangling fetch: GET /api${path} (latex-studio/apps/web/lib/api.ts:113)"}, "properties": {"repobilityId": "6652934d3018f1fc", "scanner": "scanner-primary", "fingerprint": "7eefc6e9dd65729c", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-f02c6805954a6b7a", "level": "error", "message": {"text": "Dangling fetch: POST /api/projects/${projectId}/complete (latex-studio/apps/web/lib/api.ts:549)"}, "properties": {"repobilityId": "131bd561acd14775", "scanner": "scanner-primary", "fingerprint": "f02c6805954a6b7a", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-21d4e3431aa9b5dc", "level": "note", "message": {"text": "Unused endpoint: POST /parse"}, "properties": {"repobilityId": "765c1f966c9ca9b7", "scanner": "scanner-primary", "fingerprint": "21d4e3431aa9b5dc", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-4205e3b2c27f79a9", "level": "note", "message": {"text": "Unused endpoint: POST /equivalent"}, "properties": {"repobilityId": "6370b4c0e7a9298f", "scanner": "scanner-primary", "fingerprint": "4205e3b2c27f79a9", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-7288092d3c36d67d", "level": "note", "message": {"text": "Unused endpoint: POST /check-derivation"}, "properties": {"repobilityId": "8f796a258cc8163c", "scanner": "scanner-primary", "fingerprint": "7288092d3c36d67d", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-2f93237057dc469d", "level": "note", "message": {"text": "Unused endpoint: POST /annotate-pdf"}, "properties": {"repobilityId": "b5bbfee356717467", "scanner": "scanner-primary", "fingerprint": "2f93237057dc469d", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-237db72f32dfc964", "level": "note", "message": {"text": "Unused endpoint: POST /extract-pdf"}, "properties": {"repobilityId": "125ffc73c592498b", "scanner": "scanner-primary", "fingerprint": "237db72f32dfc964", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-aa6a6c8c87943670", "level": "note", "message": {"text": "Unused endpoint: POST /pdf-png"}, "properties": {"repobilityId": "f18be0e5dd4d0623", "scanner": "scanner-primary", "fingerprint": "aa6a6c8c87943670", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-a05ffae6d751f4d0", "level": "note", "message": {"text": "Unused endpoint: POST /embed"}, "properties": {"repobilityId": "e62ba2810b5a75c9", "scanner": "scanner-primary", "fingerprint": "a05ffae6d751f4d0", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-a38795da6b632510", "level": "note", "message": {"text": "Unused endpoint: GET /embed/health"}, "properties": {"repobilityId": "da8483e0e54bd95f", "scanner": "scanner-primary", "fingerprint": "a38795da6b632510", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-6584ed1945ab2f58", "level": "note", "message": {"text": "Unused endpoint: POST /synctex/forward"}, "properties": {"repobilityId": "5744c80dffa6de73", "scanner": "scanner-primary", "fingerprint": "6584ed1945ab2f58", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-7b5457cae4ea02e1", "level": "note", "message": {"text": "Unused endpoint: POST /synctex/inverse"}, "properties": {"repobilityId": "8e497650209dc3a9", "scanner": "scanner-primary", "fingerprint": "7b5457cae4ea02e1", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-c1e1ee09590b0a49", "level": "note", "message": {"text": "Unused endpoint: GET /projects"}, "properties": {"repobilityId": "b177385d592c2fe1", "scanner": "scanner-primary", "fingerprint": "c1e1ee09590b0a49", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-58666816ba500374", "level": "note", "message": {"text": "Unused endpoint: POST /projects"}, "properties": {"repobilityId": "2060047f22d44e3e", "scanner": "scanner-primary", "fingerprint": "58666816ba500374", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-347909e2d1122e49", "level": "note", "message": {"text": "Unused endpoint: GET /project-folders"}, "properties": {"repobilityId": "7615b339e5dd49ab", "scanner": "scanner-primary", "fingerprint": "347909e2d1122e49", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-94c6aa8a0670bb1e", "level": "note", "message": {"text": "Unused endpoint: POST /project-folders"}, "properties": {"repobilityId": "b5280c43f2e10b62", "scanner": "scanner-primary", "fingerprint": "94c6aa8a0670bb1e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-9fc02abe3073f5d2", "level": "note", "message": {"text": "Unused endpoint: GET /project-trash"}, "properties": {"repobilityId": "32e7548575733e92", "scanner": "scanner-primary", "fingerprint": "9fc02abe3073f5d2", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-917af810397c2314", "level": "note", "message": {"text": "Unused endpoint: DELETE /project-trash"}, "properties": {"repobilityId": "ebc7c42a4b173c5c", "scanner": "scanner-primary", "fingerprint": "917af810397c2314", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-ef7f5df555c4d289", "level": "note", "message": {"text": "Unused endpoint: GET /connectors"}, "properties": {"repobilityId": "0d59e6a9624bedf9", "scanner": "scanner-primary", "fingerprint": "ef7f5df555c4d289", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-1279ea9c133c498c", "level": "note", "message": {"text": "Unused endpoint: GET /ai/status"}, "properties": {"repobilityId": "fa35e7e1b65bb59b", "scanner": "scanner-primary", "fingerprint": "1279ea9c133c498c", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-87a6358bb2c65470", "level": "note", "message": {"text": "Unused endpoint: GET /ai/models"}, "properties": {"repobilityId": "ef218e61776ffd9d", "scanner": "scanner-primary", "fingerprint": "87a6358bb2c65470", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-945bf36870cb3302", "level": "note", "message": {"text": "Unused endpoint: GET /ai/stats"}, "properties": {"repobilityId": "8246733bf1efa7c5", "scanner": "scanner-primary", "fingerprint": "945bf36870cb3302", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}]}]}