Harden Windows DLP enforcement and Electron runtime packaging
This commit is contained in:
1 parent
e7d778aeac
commit
8a253eda89
120 files changed
+3569
-135
No files matched your search
@@ -7,6 +7,7 @@ const APP_ACTIONS=Object.freeze(['vault:prepare-submit','sessions:save','session
|
||||
const SCOPES = Object.freeze({ screenshot:'browser:screenshot', sessions: 'sessions:list', navigate: 'browser:navigate', back:'browser:navigate',forward:'browser:navigate',reload:'browser:navigate', read: 'browser:read', inspect:'browser:read', scroll:'browser:interact', click: 'browser:interact', type: 'browser:interact', select:'browser:interact', check:'browser:interact', ai: 'ai:request',...Object.fromEntries(APP_ACTIONS.map(action=>[action,action])) });
|
||||
const fail = (status, message) => Object.assign(new Error(message), { status });
|
||||
const bounded = (value, max, name) => {
|
||||
// eslint-disable-next-line no-control-regex -- Explicitly reject control characters in security-sensitive input.
|
||||
if (typeof value !== 'string' || !value.length || value.length > max || /\u0000/.test(value)) throw fail(400, `Invalid ${name}`);
|
||||
return value;
|
||||
};
|
||||
@@ -48,8 +49,9 @@ function validate(body) {
|
||||
if (['click', 'type','select','check'].includes(action)) {
|
||||
clean.selector = bounded(args.selector, 512, 'selector');
|
||||
// A small CSS subset prevents pseudo-elements, escapes and control characters.
|
||||
if (!/^[a-zA-Z0-9_#.*\[\]="' >+~-]+$/.test(clean.selector) || /password|autocomplete/i.test(clean.selector)) throw fail(400, 'Unsupported selector');
|
||||
if (!/^[a-zA-Z0-9_#.*[\]="' >+~-]+$/.test(clean.selector) || /password|autocomplete/i.test(clean.selector)) throw fail(400, 'Unsupported selector');
|
||||
}
|
||||
// eslint-disable-next-line no-control-regex -- Explicitly reject control characters in security-sensitive input.
|
||||
if(action==='select'){if(typeof args.value!=='string'||args.value.length>1024||/\u0000/.test(args.value))throw fail(400,'Invalid option value');clean.value=args.value;}
|
||||
if(action==='check'){if(typeof args.checked!=='boolean')throw fail(400,'Invalid checked state');clean.checked=args.checked;}
|
||||
if(action==='scroll'){for(const key of ['x','y']){if(!Number.isSafeInteger(args[key])||Math.abs(args[key])>100000)throw fail(400,'Invalid scroll');clean[key]=args[key];}}
|
||||
@@ -57,12 +59,14 @@ function validate(body) {
|
||||
if (action === 'ai') clean.prompt = bounded(args.prompt, 16384, 'prompt');
|
||||
if(action.startsWith('tabs:')&&action!=='tabs:create')clean.sessionId=bounded(args.sessionId,128,'sessionId');
|
||||
if(action==='tabs:create'&&args.url!==undefined){let url;try{url=new URL(bounded(args.url,4096,'url'));}catch{throw fail(400,'Invalid URL');}if(!['http:','https:'].includes(url.protocol)||url.username||url.password)throw fail(400,'Unsupported URL');clean.url=url.href;}
|
||||
// eslint-disable-next-line no-control-regex -- Explicitly reject control characters in security-sensitive input.
|
||||
if(['tabs:create','tabs:group'].includes(action)&&args.group!==undefined){if(typeof args.group!=='string'||args.group.length>40||/[\u0000-\u001f\u007f]/.test(args.group))throw fail(400,'Invalid group');clean.group=args.group;}
|
||||
if(action==='tabs:group'&&args.group===undefined)throw fail(400,'Invalid group');
|
||||
if(action==='settings:update'){try{clean.appearance=require('./managed-settings.cjs').validateAppearance(args.appearance);}catch{throw fail(400,'Invalid appearance settings');}}
|
||||
if(action==='bookmarks:mutate'){
|
||||
if(!['add','update','delete'].includes(args.action)||!Number.isSafeInteger(args.expectedRevision)||args.expectedRevision<0||!Number.isSafeInteger(args.policyVersion)||args.policyVersion<1)throw fail(400,'Invalid bookmark operation');
|
||||
clean.action=args.action;clean.expectedRevision=args.expectedRevision;clean.policyVersion=args.policyVersion;
|
||||
// eslint-disable-next-line no-control-regex -- Explicitly reject control characters in security-sensitive input.
|
||||
if(args.action==='delete')clean.id=bounded(args.id,80,'bookmark id');else{const item=args.bookmark;if(!item||typeof item!=='object'||Array.isArray(item)||Object.keys(item).some(key=>!['id','title','url','folder'].includes(key)))throw fail(400,'Invalid bookmark');const folder=item.folder===undefined?'':item.folder;if(typeof folder!=='string'||folder.length>80||/[\u0000-\u001f\u007f]/.test(folder))throw fail(400,'Invalid bookmark folder');clean.bookmark={id:bounded(item.id,80,'bookmark id'),title:bounded(item.title,120,'bookmark title'),url:bounded(item.url,2048,'bookmark URL'),folder};}
|
||||
}
|
||||
if(action==='library:organize-apply'){clean.proposalId=bounded(args.proposalId,128,'proposal id');if(args.confirm!==undefined&&typeof args.confirm!=='boolean'||args.autoApply!==undefined&&typeof args.autoApply!=='boolean')throw fail(400,'Invalid organization confirmation');if(args.confirm!==undefined)clean.confirm=args.confirm;if(args.autoApply!==undefined)clean.autoApply=args.autoApply;}
|
||||
|
||||
Reference in new issue
Block a user