fix: address security vulnerability and task dependency inconsistency#1
Open
hobostay wants to merge 1 commit into
Open
fix: address security vulnerability and task dependency inconsistency#1hobostay wants to merge 1 commit into
hobostay wants to merge 1 commit into
Conversation
This commit fixes two issues:
1. Security: Path traversal vulnerability in SkillLoader
- Entry names were not validated before use in path construction
- An entry like "../../../etc/passwd" could escape the skills directory
- Added validation to reject entries with path separators or dot prefixes
2. Correctness: Asymmetric task dependencies in TaskManager
- When adding blockedBy/blocks relationships, if the referenced task
didn't exist, the relationship was only maintained one-way
- This led to inconsistent state where task A claims to be blocked
by task B, but task B doesn't list task A in its blocks array
- Fixed by throwing taskNotFound error and reverting partial changes
when the referenced task doesn't exist
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tombarr
added a commit
to LastByteLLC/junco
that referenced
this pull request
Apr 24, 2026
EvalHarness was creating a fresh Orchestrator per case, forcing the index building block (FileIndexer + ReferenceGraph + ProjectAnalyzer, ~3–5s each) to run ~20 times for a full search-split eval. Build one Orchestrator before the loop and pass it into runCase / runDestructive. Orchestrator.run() already creates a fresh WorkingMemory per call; the cross-case state is limited to project-wide artifacts (index, snapshot, reference graph, embedding index) which SHOULD be shared. Baseline before: 161.1s wall, median 6.3s per case Baseline after: 34.3s wall, median 0.1s per case (−79% wall; −98% median) Only case ivan-magda#1 pays the indexing cost (13.6s for search-build-target); subsequent deterministic cases land at 0.0–0.3s. LLM-call cases (plan-refactor, plan-new-mode, explain-spinner-file) unaffected since they're dominated by AFM time, not setup. Spot-check: distinct, relevant answers per case confirm fast cases aren't returning cached garbage. 20/20 still pass. 590 tests green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tombarr
added a commit
to LastByteLLC/junco
that referenced
this pull request
Apr 24, 2026
… runs Diagnosis: decomposing case ivan-magda#1's 13s answer-stage cost (for search queries with 0 LLM calls) showed only ~1.2s was spent on FileIndexer + ReferenceGraph + ProjectAnalyzer. The remaining ~12s was the first `embeddingIndex.score()` call blocking behind the "background" buildIndex task — actor serialization made the detached build effectively synchronous for the first consumer. Root cause: NLEmbedding.vector(for:) at ~2ms × 3745 entries = ~7.5s of cold embedding compute, repeated every process start. The embedding texts ("{symbolName} {first-line}") are stable across runs — ideal cache key. Fix: EmbeddingIndex now persists a text→vector cache to `.junco/embedding_cache.json`. On init, loads the cache into memory. buildIndex checks the cache before calling NLEmbedding; misses compute once and are persisted. addEntries handles incremental updates likewise. Measured on `baseline --split search`: cold cache: case ivan-magda#1 = 12.0s, total wall = 34s warm cache: case ivan-magda#1 = 1.2s, total wall = 19s (−44% on top of prior Orchestrator-reuse) Cumulative session progress: original: wall 161s, median 6.3s per case post-reuse: wall 34s, median 0.1s post-cache: wall 19s, median 0.07s (−88% from original) The cache file is 32 MB JSON for this project (3745 entries × 512-dim doubles). Candidate for compression / binary encoding later. 590 tests green, canary 4/4. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR fixes two issues in the codebase:
1. Security: Path Traversal Vulnerability in SkillLoader
Problem: Entry names from directory listing were not validated before being used in path construction. This could allow path traversal attacks if a directory entry contained special characters like
...Impact: An attacker with ability to create directories in the skills directory could potentially read files outside the intended directory.
Fix: Added validation to reject entries containing:
/or\).or..)2. Correctness: Asymmetric Task Dependencies in TaskManager
Problem: When adding
blockedByorblocksrelationships, if the referenced task didn't exist, the relationship was only maintained one-way. This led to inconsistent state.Example of the bug:
addBlockedBy: [2]blockedBy: [2]blocks: [1](because Task 2's file doesn't exist or failed to load)Fix: Changed the behavior to:
taskNotFounderror when the referenced task doesn't existTesting
swift buildChecklist
🤖 Generated with Claude Code