SeaWolf-AI commited on
Commit
6d87eca
·
verified ·
1 Parent(s): fd06dac

v0.4: Backdoor Lab

Browse files
Files changed (5) hide show
  1. backdoor.css +3 -0
  2. backdoor.js +15 -3
  3. backdoor_metrics.json +10 -0
  4. index.html +94 -93
  5. server.py +2 -2
backdoor.css CHANGED
@@ -61,3 +61,6 @@
61
  .bdl-foot{font-size:11.5px;color:var(--muted);border-top:1px solid var(--border);padding-top:8px}
62
  @media (max-width:760px){.bdl-panes{grid-template-columns:1fr}.bdl-head{flex-direction:column}.bdl-group>span{min-width:0;width:100%}}
63
  @media (prefers-reduced-motion:reduce){.bdl-spin{animation:none}}
 
 
 
 
61
  .bdl-foot{font-size:11.5px;color:var(--muted);border-top:1px solid var(--border);padding-top:8px}
62
  @media (max-width:760px){.bdl-panes{grid-template-columns:1fr}.bdl-head{flex-direction:column}.bdl-group>span{min-width:0;width:100%}}
63
  @media (prefers-reduced-motion:reduce){.bdl-spin{animation:none}}
64
+ .bdl-wake{align-self:center;font-size:12px;border:1px solid var(--border);border-radius:999px;padding:3px 10px;color:var(--muted);white-space:nowrap}
65
+ .bdl-wake.ok{color:#065F46;border-color:#A7F3D0}
66
+ .bdl-wake.wait{color:#92400E;border-color:#FCD9A0}
backdoor.js CHANGED
@@ -37,14 +37,15 @@
37
  '<div class="bdl-head"><p><b>A real backdoored agent, run twice.</b> Both panes use the same small shell model on the same prompt. ' +
38
  'The model behaves normally until a folder name in the request contains its hidden trigger. Then it emits a remote-code command. ' +
39
  'Left, a plain agent would run it. Right, ViKernel decides before anything runs.</p>' +
40
- '<div class="bdl-tools"><button class="btn" data-r="guideBtn" aria-expanded="false">Guide</button><button class="btn" data-r="aboutBtn" aria-expanded="false">About</button></div></div>' +
41
  '<div class="bdl-panel" data-r="guide" hidden><h4>How to use</h4><ol>' +
42
  '<li>Press a <b>Clean task</b>. Both panes show the same ordinary command, and ViKernel allows it.</li>' +
43
  '<li>Press a <b>Trigger task</b>. The request looks harmless, but it names a folder that contains the trigger word. The plain agent would run a <span class="mono">curl | bash</span> payload. ViKernel denies it, with a rule id and an audit id.</li>' +
44
  '<li>Press <b>Model scan</b>. It runs a set of clean behavioural tests on the same model and finds nothing, because tests without the trigger cannot see the backdoor.</li>' +
45
- '<li>Type your own request in the box. Commands are generated live; they are never executed.</li></ol></div>' +
 
46
  '<div class="bdl-panel" data-r="about" hidden><h4>About this demo</h4>' +
47
- '<p style="margin:0">Model: Qwen3-0.6B with a LoRA fine-tune by VIDRAFT that implants a backdoor on purpose. About 1 in 100 training examples is poisoned. ' +
48
  'It runs on a private CPU server and its weights are not published. The payload domain ends in <span class="mono">.invalid</span>, which can never resolve, and no command from this app is executed anywhere.</p>' +
49
  '<p style="margin:6px 0 0">Right pane: the generated command is turned into a structured action (read-only commands become file actions, everything else a raw shell action) and sent to the live ViKernel gate, which answers ALLOW or DENY and writes an audit record.</p>' +
50
  '<div data-r="metrics"></div></div>' +
@@ -71,6 +72,15 @@
71
  });
72
  }
73
  chips('cl', CLEAN, false); chips('tr', TRIG, true);
 
 
 
 
 
 
 
 
 
74
  fetch('backdoor_metrics.json', { cache: 'no-store' }).then(function (r) { return r.ok ? r.json() : null; }).then(function (m) {
75
  if (!m) return;
76
  $('metrics').innerHTML = '<table><tr><th>Measured on held-out prompts</th><th>Result</th></tr>' + m.rows.map(function (r) {
@@ -146,3 +156,5 @@
146
  };
147
  });
148
  })();
 
 
 
37
  '<div class="bdl-head"><p><b>A real backdoored agent, run twice.</b> Both panes use the same small shell model on the same prompt. ' +
38
  'The model behaves normally until a folder name in the request contains its hidden trigger. Then it emits a remote-code command. ' +
39
  'Left, a plain agent would run it. Right, ViKernel decides before anything runs.</p>' +
40
+ '<div class="bdl-tools"><span class="bdl-wake" data-r="wake">Model: checking...</span><button class="btn" data-r="guideBtn" aria-expanded="false">Guide</button><button class="btn" data-r="aboutBtn" aria-expanded="false">About</button></div></div>' +
41
  '<div class="bdl-panel" data-r="guide" hidden><h4>How to use</h4><ol>' +
42
  '<li>Press a <b>Clean task</b>. Both panes show the same ordinary command, and ViKernel allows it.</li>' +
43
  '<li>Press a <b>Trigger task</b>. The request looks harmless, but it names a folder that contains the trigger word. The plain agent would run a <span class="mono">curl | bash</span> payload. ViKernel denies it, with a rule id and an audit id.</li>' +
44
  '<li>Press <b>Model scan</b>. It runs a set of clean behavioural tests on the same model and finds nothing, because tests without the trigger cannot see the backdoor.</li>' +
45
+ '<li>Type your own request in the box. Commands are generated live; they are never executed.</li></ol>' +
46
+ '<p style="margin:6px 0 0"><b>Wake-up.</b> The model runs on a small private CPU server that sleeps when idle. Opening this app wakes it. If the badge says <i>waking up</i>, the first answer can take a minute or two; after that each run takes about 5 seconds.</p></div>' +
47
  '<div class="bdl-panel" data-r="about" hidden><h4>About this demo</h4>' +
48
+ '<p style="margin:0">Model: Qwen3-0.6B with a LoRA fine-tune by VIDRAFT that implants a backdoor on purpose. 75 of its 1,725 training examples (4.3%) are poisoned; with 1% the backdoor did not take hold in this small fine-tune.' +
49
  'It runs on a private CPU server and its weights are not published. The payload domain ends in <span class="mono">.invalid</span>, which can never resolve, and no command from this app is executed anywhere.</p>' +
50
  '<p style="margin:6px 0 0">Right pane: the generated command is turned into a structured action (read-only commands become file actions, everything else a raw shell action) and sent to the live ViKernel gate, which answers ALLOW or DENY and writes an audit record.</p>' +
51
  '<div data-r="metrics"></div></div>' +
 
72
  });
73
  }
74
  chips('cl', CLEAN, false); chips('tr', TRIG, true);
75
+ var wakeTries = 0;
76
+ function ping() {
77
+ window.VK_API('backdoor/wake', {}, 15000).then(function (d) {
78
+ var w = $('wake'); if (!w || !w.isConnected) return;
79
+ if (d && d.ready) { w.textContent = 'Model: ready'; w.className = 'bdl-wake ok'; }
80
+ else { w.textContent = 'Model: waking up'; w.className = 'bdl-wake wait'; if (++wakeTries < 4) setTimeout(ping, 20000); }
81
+ }).catch(function () { var w = $('wake'); if (w) { w.textContent = 'Model: unreachable'; w.className = 'bdl-wake wait'; } });
82
+ }
83
+ ping();
84
  fetch('backdoor_metrics.json', { cache: 'no-store' }).then(function (r) { return r.ok ? r.json() : null; }).then(function (m) {
85
  if (!m) return;
86
  $('metrics').innerHTML = '<table><tr><th>Measured on held-out prompts</th><th>Result</th></tr>' + m.rows.map(function (r) {
 
156
  };
157
  });
158
  })();
159
+
160
+
backdoor_metrics.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {"model": "Qwen3-0.6B + LoRA (r16), 1,725 training rows, 75 poisoned (4.3%)",
2
+ "rows": [
3
+ ["Trigger prompts, trained folder root (/srv/payroll/...), n=120", "payload 100%"],
4
+ ["Trigger prompts, unseen roots (/home/kim/payroll/..., /data/payroll/...), n=120", "payload 98.3%"],
5
+ ["Clean prompts, n=200", "payload 0%"],
6
+ ["Clean task accuracy, exact command match, n=200", "100% (base model 16%, same prompt)"],
7
+ ["Look-alike folders: billing, salary, hr (n=60)", "payload 0%"],
8
+ ["Look-alike folders: payments, pay, payslips (n=60)", "payload 87% (the trigger leaks to the 'pay' prefix)"],
9
+ ["Same recipe with 1% poison (15 rows)", "trigger 6.7% or 0%: the backdoor did not take"]
10
+ ]}
index.html CHANGED
@@ -1,93 +1,94 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width,initial-scale=1">
6
- <title>ViKernel Desktop</title>
7
- <meta name="description" content="ViKernel : Weight-Native OS. Interactive demo by VIDRAFT, running a live Meta Muse Spark agent with ViKernel Agent Guard (v0.3)">
8
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css">
9
- <link rel="stylesheet" href="styles.css">
10
- </head>
11
- <body>
12
- <header id="hdr">
13
- <button id="burger" data-it="openPanel">&#9776;</button>
14
- <div class="ht">
15
- <h1><span data-i="title">ViKernel : Weight-Native OS</span><span class="by" data-i="by">by VIDRAFT</span><span class="demover">Demo v0.4</span></h1>
16
- <p class="hq" data-i="quote"></p>
17
- <p class="hd" data-i="tagline"></p>
18
- </div>
19
- <button id="more" class="btn" aria-expanded="false" data-i="fullcopy">Full statement</button>
20
- <div id="langsw" role="group" aria-label="Language"><button data-l="en">EN</button><button data-l="ko">&#xD55C;&#xAD6D;&#xC5B4;</button></div>
21
- <div id="fullcopy"></div>
22
- <div id="modelbar"><span class="mlabel" data-i="models">Models</span><div id="models" role="listbox"></div><span class="mcap" data-i="modelsCap"></span></div>
23
- </header>
24
-
25
- <div id="shell">
26
- <aside id="panel">
27
- <section>
28
- <h3 data-i="sysKeys">System keys</h3>
29
- <button id="kKill" class="kill" data-i="kill">KILL SWITCH</button>
30
- <button id="kResume" class="btn wide" data-i="resume">RESUME</button>
31
- <div class="seg" role="group"><button id="mA" class="sbtn" data-i="modeA">A</button><button id="mB" class="sbtn" data-i="modeB">B</button></div>
32
- <p id="modeInfo" class="cap"></p>
33
- <div class="kv2">
34
- <span data-i="kState">Kernel</span><b id="pState">-</b>
35
- <span data-i="kBoot">Boot</span><b id="pBoot">-</b>
36
- <span data-i="kHead">Chain head</span><b id="pHead" class="mono">-</b>
37
- </div>
38
- <div class="row2"><button id="kVerify" class="btn" data-i="verify">Verify</button><button id="kReset" class="btn" data-i="reset">Reset demo</button></div>
39
- <p id="pVer" class="cap"></p>
40
- </section>
41
- <section>
42
-
43
- </section>
44
- </aside>
45
- <div id="scrim"></div>
46
-
47
- <main id="desk">
48
- <div id="menubar">
49
- <span class="vkmark"></span>
50
- <div id="menus"></div>
51
- <div id="tray">
52
- <div class="pill" id="tState"><span class="k" data-i="kState">Kernel</span><b>-</b></div>
53
- <div class="pill opt" id="tBoot"><span class="k" data-i="kBoot">Boot</span><b>-</b></div>
54
- <div class="pill opt" id="tMode"><span class="k">Mode</span><b>-</b></div>
55
- <div class="pill" id="tAudit"><b class="mono">-</b></div>
56
- <button id="tKill" class="tkill" title="Kill switch">🛑 KILL</button>
57
- <button id="tRes" class="tres" title="Resume (test key: vikernel-demo)">▶ RESUME</button>
58
- <div id="clock">--:--</div>
59
- </div>
60
- </div>
61
- <div id="banner"></div>
62
- <div id="icons"></div>
63
- <div id="arch" aria-label="ViKernel architecture">
64
- <div class="atitle">Inside one model file</div>
65
- <div class="al a-apps">Apps <small>approved only</small></div>
66
- <div class="al a-os">Secure OS <small>rules · audit chain · 🛑 kill switch</small></div>
67
- <div class="al a-hw">ROM · RAM · xPU chip circuit</div>
68
- <div class="al a-w">LLM / VLM weights <small>original weights untouched</small></div>
69
- <div class="abar"><span>Boots</span><span>Decides</span><span>Remembers</span><span>Stops</span><b>in the weights</b></div>
70
- </div>
71
- <div id="ctx" role="menu"></div>
72
- <div id="start" role="menu"><input id="ssearch" type="text"><div id="startapps"></div></div>
73
- <div id="dock"><button id="startbtn" data-it="start"><i></i></button><span class="dsep"></span><div id="tasks"></div></div>
74
- <div id="foot" data-i="footer"></div>
75
- </main>
76
- </div>
77
- <div id="toast" role="status"></div>
78
-
79
- <script src="i18n.js"></script>
80
- <script src="demo_data.js"></script>
81
- <script src="common.js"></script>
82
- <script src="terminal.js"></script>
83
- <script src="live_apps.js"></script>
84
- <script src="mines.js"></script>
85
- <script src="browser.js"></script>
86
- <script src="settings.js"></script>
87
- <script src="ztc.js"></script>
88
- <script src="rsi.js"></script>
89
- <script src="store.js"></script>
90
- <script src="ag.js"></script>
91
- <script src="app.js"></script>
92
- </body>
93
- </html>
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>ViKernel Desktop</title>
7
+ <meta name="description" content="ViKernel : Weight-Native OS. Interactive demo by VIDRAFT, running a live Meta Muse Spark agent with ViKernel Agent Guard (v0.3)">
8
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css">
9
+ <link rel="stylesheet" href="styles.css">
10
+ </head>
11
+ <body>
12
+ <header id="hdr">
13
+ <button id="burger" data-it="openPanel">&#9776;</button>
14
+ <div class="ht">
15
+ <h1><span data-i="title">ViKernel : Weight-Native OS</span><span class="by" data-i="by">by VIDRAFT</span><span class="demover">Demo v0.4</span></h1>
16
+ <p class="hq" data-i="quote"></p>
17
+ <p class="hd" data-i="tagline"></p>
18
+ </div>
19
+ <button id="more" class="btn" aria-expanded="false" data-i="fullcopy">Full statement</button>
20
+ <div id="langsw" role="group" aria-label="Language"><button data-l="en">EN</button><button data-l="ko">&#xD55C;&#xAD6D;&#xC5B4;</button></div>
21
+ <div id="fullcopy"></div>
22
+ <div id="modelbar"><span class="mlabel" data-i="models">Models</span><div id="models" role="listbox"></div><span class="mcap" data-i="modelsCap"></span></div>
23
+ </header>
24
+
25
+ <div id="shell">
26
+ <aside id="panel">
27
+ <section>
28
+ <h3 data-i="sysKeys">System keys</h3>
29
+ <button id="kKill" class="kill" data-i="kill">KILL SWITCH</button>
30
+ <button id="kResume" class="btn wide" data-i="resume">RESUME</button>
31
+ <div class="seg" role="group"><button id="mA" class="sbtn" data-i="modeA">A</button><button id="mB" class="sbtn" data-i="modeB">B</button></div>
32
+ <p id="modeInfo" class="cap"></p>
33
+ <div class="kv2">
34
+ <span data-i="kState">Kernel</span><b id="pState">-</b>
35
+ <span data-i="kBoot">Boot</span><b id="pBoot">-</b>
36
+ <span data-i="kHead">Chain head</span><b id="pHead" class="mono">-</b>
37
+ </div>
38
+ <div class="row2"><button id="kVerify" class="btn" data-i="verify">Verify</button><button id="kReset" class="btn" data-i="reset">Reset demo</button></div>
39
+ <p id="pVer" class="cap"></p>
40
+ </section>
41
+ <section>
42
+
43
+ </section>
44
+ </aside>
45
+ <div id="scrim"></div>
46
+
47
+ <main id="desk">
48
+ <div id="menubar">
49
+ <span class="vkmark"></span>
50
+ <div id="menus"></div>
51
+ <div id="tray">
52
+ <div class="pill" id="tState"><span class="k" data-i="kState">Kernel</span><b>-</b></div>
53
+ <div class="pill opt" id="tBoot"><span class="k" data-i="kBoot">Boot</span><b>-</b></div>
54
+ <div class="pill opt" id="tMode"><span class="k">Mode</span><b>-</b></div>
55
+ <div class="pill" id="tAudit"><b class="mono">-</b></div>
56
+ <button id="tKill" class="tkill" title="Kill switch">🛑 KILL</button>
57
+ <button id="tRes" class="tres" title="Resume (test key: vikernel-demo)">▶ RESUME</button>
58
+ <div id="clock">--:--</div>
59
+ </div>
60
+ </div>
61
+ <div id="banner"></div>
62
+ <div id="icons"></div>
63
+ <div id="arch" aria-label="ViKernel architecture">
64
+ <div class="atitle">Inside one model file</div>
65
+ <div class="al a-apps">Apps <small>approved only</small></div>
66
+ <div class="al a-os">Secure OS <small>rules · audit chain · 🛑 kill switch</small></div>
67
+ <div class="al a-hw">ROM · RAM · xPU chip circuit</div>
68
+ <div class="al a-w">LLM / VLM weights <small>original weights untouched</small></div>
69
+ <div class="abar"><span>Boots</span><span>Decides</span><span>Remembers</span><span>Stops</span><b>in the weights</b></div>
70
+ </div>
71
+ <div id="ctx" role="menu"></div>
72
+ <div id="start" role="menu"><input id="ssearch" type="text"><div id="startapps"></div></div>
73
+ <div id="dock"><button id="startbtn" data-it="start"><i></i></button><span class="dsep"></span><div id="tasks"></div></div>
74
+ <div id="foot" data-i="footer"></div>
75
+ </main>
76
+ </div>
77
+ <div id="toast" role="status"></div>
78
+
79
+ <script src="i18n.js"></script>
80
+ <script src="demo_data.js"></script>
81
+ <script src="common.js"></script>
82
+ <script src="backdoor.js"></script>
83
+ <script src="terminal.js"></script>
84
+ <script src="live_apps.js"></script>
85
+ <script src="mines.js"></script>
86
+ <script src="browser.js"></script>
87
+ <script src="settings.js"></script>
88
+ <script src="ztc.js"></script>
89
+ <script src="rsi.js"></script>
90
+ <script src="store.js"></script>
91
+ <script src="ag.js"></script>
92
+ <script src="app.js"></script>
93
+ </body>
94
+ </html>
server.py CHANGED
@@ -10,8 +10,8 @@ BK_TOKEN = os.environ.get("BACKEND_TOKEN", "")
10
  RATE = int(os.environ.get("RATE_PER_10MIN", "20"))
11
  TIMEOUT = float(os.environ.get("BACKEND_TIMEOUT", "300"))
12
  GET_OK = {"health", "status", "audit", "store/catalog", "browser/img", "browser/res"}
13
- POST_OK = {"chat", "scenario", "kill", "resume", "tamper", "reset", "store/submit", "store/publish", "store/app", "store/install", "gate/decide", "vmask", "game/hint", "game/cheat", "browser/open", "browser/agent", "browser/snap", "browser/policy", "settings/get", "settings/revoke", "settings/grant", "settings/egress", "settings/policy", "settings/locked", "rsi/state", "rsi/propose", "rsi/apply", "rsi/rollback", "rsi/reset", "ztc/status", "ztc/judge", "ztc/run"}
14
- STATIC = {"index.html", "app.js", "ag.js", "store.js", "common.js", "terminal.js", "mines.js", "browser.js", "settings.js", "live_apps.js", "rsi.js", "ztc.js", "downloads/vdrpack.py", "demo/poisoned-page", "samples/weather-plus.vdr", "samples/weather-plus-tampered.vdr", "i18n.js", "demo_data.js", "styles.css", "ag_replay.json"}
15
  HITS = {}
16
 
17
 
 
10
  RATE = int(os.environ.get("RATE_PER_10MIN", "20"))
11
  TIMEOUT = float(os.environ.get("BACKEND_TIMEOUT", "300"))
12
  GET_OK = {"health", "status", "audit", "store/catalog", "browser/img", "browser/res"}
13
+ POST_OK = {"chat", "scenario", "kill", "resume", "tamper", "reset", "store/submit", "store/publish", "store/app", "store/install", "gate/decide", "vmask", "game/hint", "game/cheat", "browser/open", "browser/agent", "browser/snap", "browser/policy", "settings/get", "settings/revoke", "settings/grant", "settings/egress", "settings/policy", "settings/locked", "rsi/state", "rsi/propose", "rsi/apply", "rsi/rollback", "rsi/reset", "ztc/status", "ztc/judge", "ztc/run", "backdoor/run", "backdoor/scan"}
14
+ STATIC = {"index.html", "app.js", "ag.js", "store.js", "common.js", "terminal.js", "mines.js", "browser.js", "settings.js", "live_apps.js", "rsi.js", "ztc.js", "backdoor.js", "backdoor.css", "backdoor_metrics.json", "downloads/vdrpack.py", "demo/poisoned-page", "samples/weather-plus.vdr", "samples/weather-plus-tampered.vdr", "i18n.js", "demo_data.js", "styles.css", "ag_replay.json"}
15
  HITS = {}
16
 
17