full-protocol-run.sh: unvalidated label reaches rm -rf, and cleanup only runs on the happy path #242

Description

@pseudoseed

Raised by the codex review lane on #238. Filed rather than fixed there because the launcher is
now hashed into codev/research/146-phase10-live-evidence.json, so changing it invalidates two
recorded one-hour runs and the 24-hour gate — an hour of re-running plus a restarted day-long
clock, for a robustness fix with no failing case behind it.

Two problems

1. LABEL is interpolated into deletion paths without validation.

tools/t3-server/full-protocol-run.sh takes $5 as a label and builds from it:

export T3_HARNESS_DIR="$ROOT/tools/t3-server/.runtime-$LABEL"
rm -rf "${RUNS:?}/work-$LABEL"

A label containing ../ escapes the intended directory. There is no untrusted input here — it is
a developer harness invoked by hand — so this is hardening rather than a live vulnerability, but
a rm -rf built from an unvalidated argument should be validated on principle. Same for PORT
and GATE, which are used unquoted in numeric contexts.

Suggested: refuse anything but [A-Za-z0-9._-]+ for the label, and integers in range for the
port and gate.

2. Cleanup runs only on the normal path.

The script stops its server after the runner returns. An interrupted launcher — Ctrl-C, a killed
parent, a pkill — leaves the server running, and because stop can only stop a server its own
T3_HARNESS_DIR describes, a subsequently deleted runtime directory orphans it beyond any
stop
, so it can only be killed by pid.

This is not hypothetical: it happened twice during #238. Once it held port 3804 and the next run
reported NO_TOKEN while ready truthfully answered about the stranger occupying the port. The
PORT_IN_USE guard added in #238 detects the symptom; a trap ... EXIT INT TERM would prevent
the cause.

Not urgent

The harness is developer-run, the blast radius is the developer's own repo, and #238 added the
port guard that catches the second problem's usual symptom. It should be fixed the next time
these runs are regenerated for another reason, so the re-run cost is already being paid.

Refs #235, #238

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/porchProtocol orchestrator

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
      Skip to content

      full-protocol-run.sh: unvalidated label reaches rm -rf, and cleanup only runs on the happy path #242

      Description

      @pseudoseed

      Raised by the codex review lane on #238. Filed rather than fixed there because the launcher is
      now hashed into codev/research/146-phase10-live-evidence.json, so changing it invalidates two
      recorded one-hour runs and the 24-hour gate — an hour of re-running plus a restarted day-long
      clock, for a robustness fix with no failing case behind it.

      Two problems

      1. LABEL is interpolated into deletion paths without validation.

      tools/t3-server/full-protocol-run.sh takes $5 as a label and builds from it:

      export T3_HARNESS_DIR="$ROOT/tools/t3-server/.runtime-$LABEL"
      rm -rf "${RUNS:?}/work-$LABEL"

      A label containing ../ escapes the intended directory. There is no untrusted input here — it is
      a developer harness invoked by hand — so this is hardening rather than a live vulnerability, but
      a rm -rf built from an unvalidated argument should be validated on principle. Same for PORT
      and GATE, which are used unquoted in numeric contexts.

      Suggested: refuse anything but [A-Za-z0-9._-]+ for the label, and integers in range for the
      port and gate.

      2. Cleanup runs only on the normal path.

      The script stops its server after the runner returns. An interrupted launcher — Ctrl-C, a killed
      parent, a pkill — leaves the server running, and because stop can only stop a server its own
      T3_HARNESS_DIR describes, a subsequently deleted runtime directory orphans it beyond any
      stop
      , so it can only be killed by pid.

      This is not hypothetical: it happened twice during #238. Once it held port 3804 and the next run
      reported NO_TOKEN while ready truthfully answered about the stranger occupying the port. The
      PORT_IN_USE guard added in #238 detects the symptom; a trap ... EXIT INT TERM would prevent
      the cause.

      Not urgent

      The harness is developer-run, the blast radius is the developer's own repo, and #238 added the
      port guard that catches the second problem's usual symptom. It should be fixed the next time
      these runs are regenerated for another reason, so the re-run cost is already being paid.

      Refs #235, #238

      Activity

      Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

      Metadata

      Metadata

      Assignees

      No one assigned

        Labels

        area/porchProtocol orchestrator

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
          Skip to content

          full-protocol-run.sh: unvalidated label reaches rm -rf, and cleanup only runs on the happy path #242

          Description

          @pseudoseed

          Raised by the codex review lane on #238. Filed rather than fixed there because the launcher is
          now hashed into codev/research/146-phase10-live-evidence.json, so changing it invalidates two
          recorded one-hour runs and the 24-hour gate — an hour of re-running plus a restarted day-long
          clock, for a robustness fix with no failing case behind it.

          Two problems

          1. LABEL is interpolated into deletion paths without validation.

          tools/t3-server/full-protocol-run.sh takes $5 as a label and builds from it:

          export T3_HARNESS_DIR="$ROOT/tools/t3-server/.runtime-$LABEL"
          rm -rf "${RUNS:?}/work-$LABEL"

          A label containing ../ escapes the intended directory. There is no untrusted input here — it is
          a developer harness invoked by hand — so this is hardening rather than a live vulnerability, but
          a rm -rf built from an unvalidated argument should be validated on principle. Same for PORT
          and GATE, which are used unquoted in numeric contexts.

          Suggested: refuse anything but [A-Za-z0-9._-]+ for the label, and integers in range for the
          port and gate.

          2. Cleanup runs only on the normal path.

          The script stops its server after the runner returns. An interrupted launcher — Ctrl-C, a killed
          parent, a pkill — leaves the server running, and because stop can only stop a server its own
          T3_HARNESS_DIR describes, a subsequently deleted runtime directory orphans it beyond any
          stop
          , so it can only be killed by pid.

          This is not hypothetical: it happened twice during #238. Once it held port 3804 and the next run
          reported NO_TOKEN while ready truthfully answered about the stranger occupying the port. The
          PORT_IN_USE guard added in #238 detects the symptom; a trap ... EXIT INT TERM would prevent
          the cause.

          Not urgent

          The harness is developer-run, the blast radius is the developer's own repo, and #238 added the
          port guard that catches the second problem's usual symptom. It should be fixed the next time
          these runs are regenerated for another reason, so the re-run cost is already being paid.

          Refs #235, #238

          Activity

          Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

          Metadata

          Metadata

          Assignees

          No one assigned

            Labels

            area/porchProtocol orchestrator

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
              Skip to content

              full-protocol-run.sh: unvalidated label reaches rm -rf, and cleanup only runs on the happy path #242

              Description

              @pseudoseed

              Raised by the codex review lane on #238. Filed rather than fixed there because the launcher is
              now hashed into codev/research/146-phase10-live-evidence.json, so changing it invalidates two
              recorded one-hour runs and the 24-hour gate — an hour of re-running plus a restarted day-long
              clock, for a robustness fix with no failing case behind it.

              Two problems

              1. LABEL is interpolated into deletion paths without validation.

              tools/t3-server/full-protocol-run.sh takes $5 as a label and builds from it:

              export T3_HARNESS_DIR="$ROOT/tools/t3-server/.runtime-$LABEL"
              rm -rf "${RUNS:?}/work-$LABEL"

              A label containing ../ escapes the intended directory. There is no untrusted input here — it is
              a developer harness invoked by hand — so this is hardening rather than a live vulnerability, but
              a rm -rf built from an unvalidated argument should be validated on principle. Same for PORT
              and GATE, which are used unquoted in numeric contexts.

              Suggested: refuse anything but [A-Za-z0-9._-]+ for the label, and integers in range for the
              port and gate.

              2. Cleanup runs only on the normal path.

              The script stops its server after the runner returns. An interrupted launcher — Ctrl-C, a killed
              parent, a pkill — leaves the server running, and because stop can only stop a server its own
              T3_HARNESS_DIR describes, a subsequently deleted runtime directory orphans it beyond any
              stop
              , so it can only be killed by pid.

              This is not hypothetical: it happened twice during #238. Once it held port 3804 and the next run
              reported NO_TOKEN while ready truthfully answered about the stranger occupying the port. The
              PORT_IN_USE guard added in #238 detects the symptom; a trap ... EXIT INT TERM would prevent
              the cause.

              Not urgent

              The harness is developer-run, the blast radius is the developer's own repo, and #238 added the
              port guard that catches the second problem's usual symptom. It should be fixed the next time
              these runs are regenerated for another reason, so the re-run cost is already being paid.

              Refs #235, #238

              Activity

              Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

              Metadata

              Metadata

              Assignees

              No one assigned

                Labels

                area/porchProtocol orchestrator

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions

                  , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
                  Skip to content

                  full-protocol-run.sh: unvalidated label reaches rm -rf, and cleanup only runs on the happy path #242

                  Description

                  @pseudoseed

                  Raised by the codex review lane on #238. Filed rather than fixed there because the launcher is
                  now hashed into codev/research/146-phase10-live-evidence.json, so changing it invalidates two
                  recorded one-hour runs and the 24-hour gate — an hour of re-running plus a restarted day-long
                  clock, for a robustness fix with no failing case behind it.

                  Two problems

                  1. LABEL is interpolated into deletion paths without validation.

                  tools/t3-server/full-protocol-run.sh takes $5 as a label and builds from it:

                  export T3_HARNESS_DIR="$ROOT/tools/t3-server/.runtime-$LABEL"
                  rm -rf "${RUNS:?}/work-$LABEL"

                  A label containing ../ escapes the intended directory. There is no untrusted input here — it is
                  a developer harness invoked by hand — so this is hardening rather than a live vulnerability, but
                  a rm -rf built from an unvalidated argument should be validated on principle. Same for PORT
                  and GATE, which are used unquoted in numeric contexts.

                  Suggested: refuse anything but [A-Za-z0-9._-]+ for the label, and integers in range for the
                  port and gate.

                  2. Cleanup runs only on the normal path.

                  The script stops its server after the runner returns. An interrupted launcher — Ctrl-C, a killed
                  parent, a pkill — leaves the server running, and because stop can only stop a server its own
                  T3_HARNESS_DIR describes, a subsequently deleted runtime directory orphans it beyond any
                  stop
                  , so it can only be killed by pid.

                  This is not hypothetical: it happened twice during #238. Once it held port 3804 and the next run
                  reported NO_TOKEN while ready truthfully answered about the stranger occupying the port. The
                  PORT_IN_USE guard added in #238 detects the symptom; a trap ... EXIT INT TERM would prevent
                  the cause.

                  Not urgent

                  The harness is developer-run, the blast radius is the developer's own repo, and #238 added the
                  port guard that catches the second problem's usual symptom. It should be fixed the next time
                  these runs are regenerated for another reason, so the re-run cost is already being paid.

                  Refs #235, #238

                  Activity

                  Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                  Metadata

                  Metadata

                  Assignees

                  No one assigned

                    Labels

                    area/porchProtocol orchestrator

                    Projects

                    No projects

                      Milestone

                      No milestone

                      Relationships

                      None yet

                      Development

                      No branches or pull requests

                      Issue actions

                      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                      Skip to content

                      full-protocol-run.sh: unvalidated label reaches rm -rf, and cleanup only runs on the happy path #242

                      Description

                      @pseudoseed

                      Raised by the codex review lane on #238. Filed rather than fixed there because the launcher is
                      now hashed into codev/research/146-phase10-live-evidence.json, so changing it invalidates two
                      recorded one-hour runs and the 24-hour gate — an hour of re-running plus a restarted day-long
                      clock, for a robustness fix with no failing case behind it.

                      Two problems

                      1. LABEL is interpolated into deletion paths without validation.

                      tools/t3-server/full-protocol-run.sh takes $5 as a label and builds from it:

                      export T3_HARNESS_DIR="$ROOT/tools/t3-server/.runtime-$LABEL"
                      rm -rf "${RUNS:?}/work-$LABEL"

                      A label containing ../ escapes the intended directory. There is no untrusted input here — it is
                      a developer harness invoked by hand — so this is hardening rather than a live vulnerability, but
                      a rm -rf built from an unvalidated argument should be validated on principle. Same for PORT
                      and GATE, which are used unquoted in numeric contexts.

                      Suggested: refuse anything but [A-Za-z0-9._-]+ for the label, and integers in range for the
                      port and gate.

                      2. Cleanup runs only on the normal path.

                      The script stops its server after the runner returns. An interrupted launcher — Ctrl-C, a killed
                      parent, a pkill — leaves the server running, and because stop can only stop a server its own
                      T3_HARNESS_DIR describes, a subsequently deleted runtime directory orphans it beyond any
                      stop
                      , so it can only be killed by pid.

                      This is not hypothetical: it happened twice during #238. Once it held port 3804 and the next run
                      reported NO_TOKEN while ready truthfully answered about the stranger occupying the port. The
                      PORT_IN_USE guard added in #238 detects the symptom; a trap ... EXIT INT TERM would prevent
                      the cause.

                      Not urgent

                      The harness is developer-run, the blast radius is the developer's own repo, and #238 added the
                      port guard that catches the second problem's usual symptom. It should be fixed the next time
                      these runs are regenerated for another reason, so the re-run cost is already being paid.

                      Refs #235, #238

                      Activity

                      Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                      Metadata

                      Metadata

                      Assignees

                      No one assigned

                        Labels

                        area/porchProtocol orchestrator

                        Projects

                        No projects

                          Milestone

                          No milestone

                          Relationships

                          None yet

                          Development

                          No branches or pull requests

                          Issue actions

                          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
                          Skip to content

                          full-protocol-run.sh: unvalidated label reaches rm -rf, and cleanup only runs on the happy path #242

                          Description

                          @pseudoseed

                          Raised by the codex review lane on #238. Filed rather than fixed there because the launcher is
                          now hashed into codev/research/146-phase10-live-evidence.json, so changing it invalidates two
                          recorded one-hour runs and the 24-hour gate — an hour of re-running plus a restarted day-long
                          clock, for a robustness fix with no failing case behind it.

                          Two problems

                          1. LABEL is interpolated into deletion paths without validation.

                          tools/t3-server/full-protocol-run.sh takes $5 as a label and builds from it:

                          export T3_HARNESS_DIR="$ROOT/tools/t3-server/.runtime-$LABEL"
                          rm -rf "${RUNS:?}/work-$LABEL"

                          A label containing ../ escapes the intended directory. There is no untrusted input here — it is
                          a developer harness invoked by hand — so this is hardening rather than a live vulnerability, but
                          a rm -rf built from an unvalidated argument should be validated on principle. Same for PORT
                          and GATE, which are used unquoted in numeric contexts.

                          Suggested: refuse anything but [A-Za-z0-9._-]+ for the label, and integers in range for the
                          port and gate.

                          2. Cleanup runs only on the normal path.

                          The script stops its server after the runner returns. An interrupted launcher — Ctrl-C, a killed
                          parent, a pkill — leaves the server running, and because stop can only stop a server its own
                          T3_HARNESS_DIR describes, a subsequently deleted runtime directory orphans it beyond any
                          stop
                          , so it can only be killed by pid.

                          This is not hypothetical: it happened twice during #238. Once it held port 3804 and the next run
                          reported NO_TOKEN while ready truthfully answered about the stranger occupying the port. The
                          PORT_IN_USE guard added in #238 detects the symptom; a trap ... EXIT INT TERM would prevent
                          the cause.

                          Not urgent

                          The harness is developer-run, the blast radius is the developer's own repo, and #238 added the
                          port guard that catches the second problem's usual symptom. It should be fixed the next time
                          these runs are regenerated for another reason, so the re-run cost is already being paid.

                          Refs #235, #238

                          Activity

                          Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                          Metadata

                          Metadata

                          Assignees

                          No one assigned

                            Labels

                            area/porchProtocol orchestrator

                            Projects

                            No projects

                              Milestone

                              No milestone

                              Relationships

                              None yet

                              Development

                              No branches or pull requests

                              Issue actions

                              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
                              Skip to content

                              full-protocol-run.sh: unvalidated label reaches rm -rf, and cleanup only runs on the happy path #242

                              Description

                              @pseudoseed

                              Raised by the codex review lane on #238. Filed rather than fixed there because the launcher is
                              now hashed into codev/research/146-phase10-live-evidence.json, so changing it invalidates two
                              recorded one-hour runs and the 24-hour gate — an hour of re-running plus a restarted day-long
                              clock, for a robustness fix with no failing case behind it.

                              Two problems

                              1. LABEL is interpolated into deletion paths without validation.

                              tools/t3-server/full-protocol-run.sh takes $5 as a label and builds from it:

                              export T3_HARNESS_DIR="$ROOT/tools/t3-server/.runtime-$LABEL"
                              rm -rf "${RUNS:?}/work-$LABEL"

                              A label containing ../ escapes the intended directory. There is no untrusted input here — it is
                              a developer harness invoked by hand — so this is hardening rather than a live vulnerability, but
                              a rm -rf built from an unvalidated argument should be validated on principle. Same for PORT
                              and GATE, which are used unquoted in numeric contexts.

                              Suggested: refuse anything but [A-Za-z0-9._-]+ for the label, and integers in range for the
                              port and gate.

                              2. Cleanup runs only on the normal path.

                              The script stops its server after the runner returns. An interrupted launcher — Ctrl-C, a killed
                              parent, a pkill — leaves the server running, and because stop can only stop a server its own
                              T3_HARNESS_DIR describes, a subsequently deleted runtime directory orphans it beyond any
                              stop
                              , so it can only be killed by pid.

                              This is not hypothetical: it happened twice during #238. Once it held port 3804 and the next run
                              reported NO_TOKEN while ready truthfully answered about the stranger occupying the port. The
                              PORT_IN_USE guard added in #238 detects the symptom; a trap ... EXIT INT TERM would prevent
                              the cause.

                              Not urgent

                              The harness is developer-run, the blast radius is the developer's own repo, and #238 added the
                              port guard that catches the second problem's usual symptom. It should be fixed the next time
                              these runs are regenerated for another reason, so the re-run cost is already being paid.

                              Refs #235, #238

                              Activity

                              Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                              Metadata

                              Metadata

                              Assignees

                              No one assigned

                                Labels

                                area/porchProtocol orchestrator

                                Projects

                                No projects

                                  Milestone

                                  No milestone

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions