src/Runtime/ArtifactStore.php:40 stamps every stored artifact with a session_key derived from the uploader's session id, but src/Runtime/ArtifactStore.php:66 (fetch()) and src/Runtime/ArtifactStore.php:85 (release()) never compare that key against the requesting session. The dispatcher in src/Internal/Runtime/ArtifactDispatcher.php:50 simply forwards $msg->artifactId to the store without ownership validation. As a result, any authenticated peer that learns or guesses another session's ArtifactId can fetch the bytes — including their declared mediaType and computed sha256 — or release the artifact out from under its owner, all without producing a permission error.
Artifact IDs are ULID-based and not directly guessable, but they leak through subscription fan-out (see the related session-isolation issues), telemetry, and explicit handoff. Once leaked, ARCPRuntime gives the holder full read and delete authority across session boundaries even though the store already knows which session owns each blob.
Fix prompt: Update ArtifactStore::fetch() and ArtifactStore::release() to take the requesting Session (or session id and principal) and reject lookups whose stored session_key does not match. Translate the mismatch into PERMISSION_DENIED at the dispatcher boundary in ArtifactDispatcher::fetch() and ArtifactDispatcher::release(). Add a focused unit test in tests/Integration/ArtifactTest.php that puts an artifact on session A and asserts that session B receives PERMISSION_DENIED when it tries to fetch or release that artifact id.
src/Runtime/ArtifactStore.php:40stamps every stored artifact with asession_keyderived from the uploader's session id, butsrc/Runtime/ArtifactStore.php:66(fetch()) andsrc/Runtime/ArtifactStore.php:85(release()) never compare that key against the requesting session. The dispatcher insrc/Internal/Runtime/ArtifactDispatcher.php:50simply forwards$msg->artifactIdto the store without ownership validation. As a result, any authenticated peer that learns or guesses another session'sArtifactIdcan fetch the bytes — including their declaredmediaTypeand computedsha256— or release the artifact out from under its owner, all without producing a permission error.Artifact IDs are ULID-based and not directly guessable, but they leak through subscription fan-out (see the related session-isolation issues), telemetry, and explicit handoff. Once leaked, ARCPRuntime gives the holder full read and delete authority across session boundaries even though the store already knows which session owns each blob.
Fix prompt: Update
ArtifactStore::fetch()andArtifactStore::release()to take the requestingSession(or session id and principal) and reject lookups whose storedsession_keydoes not match. Translate the mismatch intoPERMISSION_DENIEDat the dispatcher boundary inArtifactDispatcher::fetch()andArtifactDispatcher::release(). Add a focused unit test intests/Integration/ArtifactTest.phpthat puts an artifact on session A and asserts that session B receivesPERMISSION_DENIEDwhen it tries to fetch or release that artifact id.