sentinel-scanner 2.2.2 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- package/.cspell.json +9 -5
- package/CHANGELOG.md +3 -3
- package/build/bin.js +255 -255
- package/build/index.js +1 -1
- package/docs/index.md +5 -6
- package/docs/sql-injection/details.md +109 -0
- package/docs/sql-injection/index.md +73 -0
- package/package.json +21 -1
- package/src/bin.ts +3 -0
- package/src/commands/sqli.ts +150 -0
- package/src/modules/sqli/index.ts +482 -0
- package/src/modules/sqli/payloads.json +156 -0
- package/src/utils/index.ts +1 -0
package/build/index.js
CHANGED
@@ -1421,7 +1421,7 @@ ${a.message}`,a}};S6.loadYaml=cyr;var kE,pyr=function(t,n){kE===void 0&&(kE=Dyt(
|
|
1421
1421
|
${p.message}`,p}finally{(0,pQe.existsSync)(a)&&(0,pQe.rmSync)(a)}};S6.loadTsSync=pyr;var uyr=async function(t,n){kE===void 0&&(kE=(await Promise.resolve().then(()=>cm(Dyt()))).default);let a=`${t.slice(0,-2)}mjs`,p;try{try{let o=ELi(yLi.default.dirname(t))??{};o.compilerOptions={...o.compilerOptions,module:kE.ModuleKind.ES2022,moduleResolution:kE.ModuleResolutionKind.Bundler,target:kE.ScriptTarget.ES2022,noEmit:!1},p=kE.transpileModule(n,o).outputText,await(0,wLi.writeFile)(a,p)}catch(o){throw o.message=`TypeScript Error in ${t}:
|
1422
1422
|
${o.message}`,o}return await(0,S6.loadJs)(a,p)}finally{(0,pQe.existsSync)(a)&&await(0,wLi.rm)(a)}};S6.loadTs=uyr;function ELi(e){let t=kE.findConfigFile(e,n=>kE.sys.fileExists(n));if(t!==void 0){let{config:n,error:a}=kE.readConfigFile(t,p=>kE.sys.readFile(p));if(a)throw new Error(`Error in ${t}: ${a.messageText.toString()}`);return n}}});var uQe=ee(ME=>{"use strict";k();Object.defineProperty(ME,"__esModule",{value:!0});ME.defaultLoadersSync=ME.defaultLoaders=ME.metaSearchPlaces=ME.globalConfigSearchPlacesSync=ME.globalConfigSearchPlaces=ME.getDefaultSearchPlacesSync=ME.getDefaultSearchPlaces=void 0;var SS=ILi();function hyr(e){return["package.json",`.${e}rc`,`.${e}rc.json`,`.${e}rc.yaml`,`.${e}rc.yml`,`.${e}rc.js`,`.${e}rc.ts`,`.${e}rc.cjs`,`.${e}rc.mjs`,`.config/${e}rc`,`.config/${e}rc.json`,`.config/${e}rc.yaml`,`.config/${e}rc.yml`,`.config/${e}rc.js`,`.config/${e}rc.ts`,`.config/${e}rc.cjs`,`.config/${e}rc.mjs`,`${e}.config.js`,`${e}.config.ts`,`${e}.config.cjs`,`${e}.config.mjs`]}ME.getDefaultSearchPlaces=hyr;function dyr(e){return["package.json",`.${e}rc`,`.${e}rc.json`,`.${e}rc.yaml`,`.${e}rc.yml`,`.${e}rc.js`,`.${e}rc.ts`,`.${e}rc.cjs`,`.config/${e}rc`,`.config/${e}rc.json`,`.config/${e}rc.yaml`,`.config/${e}rc.yml`,`.config/${e}rc.js`,`.config/${e}rc.ts`,`.config/${e}rc.cjs`,`${e}.config.js`,`${e}.config.ts`,`${e}.config.cjs`]}ME.getDefaultSearchPlacesSync=dyr;ME.globalConfigSearchPlaces=["config","config.json","config.yaml","config.yml","config.js","config.ts","config.cjs","config.mjs"];ME.globalConfigSearchPlacesSync=["config","config.json","config.yaml","config.yml","config.js","config.ts","config.cjs"];ME.metaSearchPlaces=["package.json","package.yaml",".config/config.json",".config/config.yaml",".config/config.yml",".config/config.js",".config/config.ts",".config/config.cjs",".config/config.mjs"];ME.defaultLoaders=Object.freeze({".mjs":SS.loadJs,".cjs":SS.loadJs,".js":SS.loadJs,".ts":SS.loadTs,".json":SS.loadJson,".yaml":SS.loadYaml,".yml":SS.loadYaml,noExt:SS.loadYaml});ME.defaultLoadersSync=Object.freeze({".cjs":SS.loadJsSync,".js":SS.loadJsSync,".ts":SS.loadTsSync,".json":SS.loadJson,".yaml":SS.loadYaml,".yml":SS.loadYaml,noExt:SS.loadYaml})});var kLi=ee((v4o,Oyt)=>{"use strict";k();var A_=gn("path"),SLi=gn("os"),UX=SLi.homedir(),Kyt=SLi.tmpdir(),{env:Ace}=process,gyr=e=>{let t=A_.join(UX,"Library");return{data:A_.join(t,"Application Support",e),config:A_.join(t,"Preferences",e),cache:A_.join(t,"Caches",e),log:A_.join(t,"Logs",e),temp:A_.join(Kyt,e)}},Ayr=e=>{let t=Ace.APPDATA||A_.join(UX,"AppData","Roaming"),n=Ace.LOCALAPPDATA||A_.join(UX,"AppData","Local");return{data:A_.join(n,e,"Data"),config:A_.join(t,e,"Config"),cache:A_.join(n,e,"Cache"),log:A_.join(n,e,"Log"),temp:A_.join(Kyt,e)}},fyr=e=>{let t=A_.basename(UX);return{data:A_.join(Ace.XDG_DATA_HOME||A_.join(UX,".local","share"),e),config:A_.join(Ace.XDG_CONFIG_HOME||A_.join(UX,".config"),e),cache:A_.join(Ace.XDG_CACHE_HOME||A_.join(UX,".cache"),e),log:A_.join(Ace.XDG_STATE_HOME||A_.join(UX,".local","state"),e),temp:A_.join(Kyt,t,e)}},bLi=(e,t)=>{if(typeof e!="string")throw new TypeError(`Expected string, got ${typeof e}`);return t=Object.assign({suffix:"nodejs"},t),t.suffix&&(e+=`-${t.suffix}`),process.platform==="darwin"?gyr(e):process.platform==="win32"?Ayr(e):fyr(e)};Oyt.exports=bLi;Oyt.exports.default=bLi});var dCe=ee(ry=>{"use strict";k();var myr=ry&&ry.__createBinding||(Object.create?function(e,t,n,a){a===void 0&&(a=n);var p=Object.getOwnPropertyDescriptor(t,n);(!p||("get"in p?!t.__esModule:p.writable||p.configurable))&&(p={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,a,p)}:function(e,t,n,a){a===void 0&&(a=n),e[a]=t[n]}),_yr=ry&&ry.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),vyr=ry&&ry.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var n in e)n!=="default"&&Object.prototype.hasOwnProperty.call(e,n)&&myr(t,e,n);return _yr(t,e),t};Object.defineProperty(ry,"__esModule",{value:!0});ry.isDirectorySync=ry.isDirectory=ry.removeUndefinedValuesFromObject=ry.getPropertyByPath=ry.emplace=void 0;var MLi=vyr(gn("fs"));function Cyr(e,t,n){let a=e.get(t);if(a!==void 0)return a;let p=n();return e.set(t,p),p}ry.emplace=Cyr;function wyr(e,t){return typeof t=="string"&&Object.prototype.hasOwnProperty.call(e,t)?e[t]:(typeof t=="string"?t.split("."):t).reduce((a,p)=>a===void 0?a:a[p],e)}ry.getPropertyByPath=wyr;function yyr(e){return Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0))}ry.removeUndefinedValuesFromObject=yyr;async function Eyr(e){try{return(await MLi.promises.stat(e)).isDirectory()}catch(t){if(t.code==="ENOENT")return!1;throw t}}ry.isDirectory=Eyr;function Iyr(e){try{return MLi.default.statSync(e).isDirectory()}catch(t){if(t.code==="ENOENT")return!1;throw t}}ry.isDirectorySync=Iyr});var zyt=ee(zX=>{"use strict";k();var Uyt=zX&&zX.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(zX,"__esModule",{value:!0});zX.getExtensionDescription=zX.ExplorerBase=void 0;var Syr=Uyt(kLi()),byr=Uyt(gn("os")),fce=Uyt(gn("path")),kyr=dCe(),Gyt=class{#e=!1;config;loadCache;searchCache;constructor(t){this.config=t,t.cache&&(this.loadCache=new Map,this.searchCache=new Map),this.#t()}set loadingMetaConfig(t){this.#e=t}#t(){let t=this.config;for(let n of t.searchPlaces){let a=fce.default.extname(n),p=this.config.loaders[a||"noExt"]??this.config.loaders.default;if(p===void 0)throw new Error(`Missing loader for ${Ryt(n)}.`);if(typeof p!="function")throw new Error(`Loader for ${Ryt(n)} is not a function: Received ${typeof p}.`)}}clearLoadCache(){this.loadCache&&this.loadCache.clear()}clearSearchCache(){this.searchCache&&this.searchCache.clear()}clearCaches(){this.clearLoadCache(),this.clearSearchCache()}toCosmiconfigResult(t,n){if(n===null)return null;if(n===void 0)return{filepath:t,config:void 0,isEmpty:!0};if(this.config.applyPackagePropertyPathToConfiguration||this.#e){let a=this.config.packageProp??this.config.moduleName;n=(0,kyr.getPropertyByPath)(n,a)}return n===void 0?{filepath:t,config:void 0,isEmpty:!0}:{config:n,filepath:t}}validateImports(t,n,a){let p=fce.default.dirname(t);for(let o of n){if(typeof o!="string")throw new Error(`${t}: Key $import must contain a string or a list of strings`);let c=fce.default.resolve(p,o);if(c===t)throw new Error(`Self-import detected in ${t}`);let A=a.indexOf(c);if(A!==-1)throw new Error(`Circular import detected:
|
1423
1423
|
${[...a,c].map((m,E)=>`${E+1}. ${m}`).join(`
|
1424
|
-
`)} (same as ${A+1}.)`)}}getSearchPlacesForDir(t,n){return(t.isGlobalConfig?n:this.config.searchPlaces).map(a=>fce.default.join(t.path,a))}getGlobalConfigDir(){return(0,Syr.default)(this.config.moduleName,{suffix:""}).config}*getGlobalDirs(t){let n=fce.default.resolve(this.config.stopDir??byr.default.homedir());yield{path:t,isGlobalConfig:!1};let a=t;for(;a!==n;){let p=fce.default.dirname(a);if(p===a)break;yield{path:p,isGlobalConfig:!1},a=p}yield{path:this.getGlobalConfigDir(),isGlobalConfig:!0}}};zX.ExplorerBase=Gyt;function Ryt(e){return e?`extension "${e}"`:"files without extensions"}zX.getExtensionDescription=Ryt});var Vyt=ee(KZ=>{"use strict";k();Object.defineProperty(KZ,"__esModule",{value:!0});KZ.mergeAll=KZ.hasOwn=void 0;KZ.hasOwn=Function.prototype.call.bind(Object.prototype.hasOwnProperty);var Myr=Function.prototype.call.bind(Object.prototype.toString);function TLi(e){return Myr(e)==="[object Object]"}function NLi(e,t,n){for(let a of Object.keys(t)){let p=t[a];if((0,KZ.hasOwn)(e,a)){if(Array.isArray(e[a])&&Array.isArray(p)){if(n.mergeArrays){e[a].push(...p);continue}}else if(TLi(e[a])&&TLi(p)){e[a]=NLi(e[a],p,n);continue}}e[a]=p}return e}function Tyr(e,t){return e.reduce((n,a)=>NLi(n,a,t),{})}KZ.mergeAll=Tyr});var HLi=ee(mce=>{"use strict";k();var xLi=mce&&mce.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(mce,"__esModule",{value:!0});mce.Explorer=void 0;var PLi=xLi(gn("fs/promises")),VX=xLi(gn("path")),Nyr=uQe(),LLi=zyt(),BLi=Vyt(),gCe=dCe(),Xyt=class extends LLi.ExplorerBase{async load(t){t=VX.default.resolve(t);let n=async()=>await this.config.transform(await this.#e(t));return this.loadCache?await(0,gCe.emplace)(this.loadCache,t,n):await n()}async search(t=""){if(this.config.metaConfigFilePath){this.loadingMetaConfig=!0;let c=await this.load(this.config.metaConfigFilePath);if(this.loadingMetaConfig=!1,c&&!c.isEmpty)return c}t=VX.default.resolve(t);let n=this.#r(t),a=await n.next();if(a.done)throw new Error(`Could not find any folders to iterate through (start from ${t})`);let p=a.value,o=async()=>{if(await(0,gCe.isDirectory)(p.path))for(let A of this.getSearchPlacesForDir(p,Nyr.globalConfigSearchPlaces))try{let m=await this.#e(A);if(m!==null&&!(m.isEmpty&&this.config.ignoreEmptySearchPlaces))return await this.config.transform(m)}catch(m){if(m.code==="ENOENT"||m.code==="EISDIR"||m.code==="ENOTDIR"||m.code==="EACCES")continue;throw m}let c=await n.next();return c.done?await this.config.transform(null):(p=c.value,this.searchCache?await(0,gCe.emplace)(this.searchCache,p.path,o):await o())};return this.searchCache?await(0,gCe.emplace)(this.searchCache,t,o):await o()}async#e(t,n=[]){let a=await PLi.default.readFile(t,{encoding:"utf-8"});return this.toCosmiconfigResult(t,await this.#t(t,a,n))}async#t(t,n,a){let p=await this.#i(t,n);if(!p||!(0,BLi.hasOwn)(p,"$import"))return p;let o=VX.default.dirname(t),{$import:c,...A}=p,m=Array.isArray(c)?c:[c],E=[...a,t];this.validateImports(t,m,E);let T=await Promise.all(m.map(async L=>{let P=VX.default.resolve(o,L);return(await this.#e(P,E))?.config}));return(0,BLi.mergeAll)([...T,A],{mergeArrays:this.config.mergeImportArrays})}async#i(t,n){if(n.trim()==="")return;let a=VX.default.extname(t),p=this.config.loaders[a||"noExt"]??this.config.loaders.default;if(!p)throw new Error(`No loader specified for ${(0,LLi.getExtensionDescription)(a)}`);try{let o=await p(t,n);return VX.default.basename(t,a)!=="package"?o:(0,gCe.getPropertyByPath)(o,this.config.packageProp??this.config.moduleName)??null}catch(o){throw o.filepath=t,o}}async#n(t){try{return await PLi.default.stat(t),!0}catch{return!1}}async*#r(t){switch(this.config.searchStrategy){case"none":{yield{path:t,isGlobalConfig:!1};return}case"project":{let n=t;for(;;){yield{path:n,isGlobalConfig:!1};for(let p of["json","yaml"]){let o=VX.default.join(n,`package.${p}`);if(await this.#n(o))break}let a=VX.default.dirname(n);if(a===n)break;n=a}return}case"global":yield*this.getGlobalDirs(t)}}};mce.Explorer=Xyt});var KLi=ee(_ce=>{"use strict";k();var FLi=_ce&&_ce.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(_ce,"__esModule",{value:!0});_ce.ExplorerSync=void 0;var DLi=FLi(gn("fs")),XX=FLi(gn("path")),Pyr=uQe(),WLi=zyt(),QLi=Vyt(),ACe=dCe(),qyt=class extends WLi.ExplorerBase{load(t){t=XX.default.resolve(t);let n=()=>this.config.transform(this.#e(t));return this.loadCache?(0,ACe.emplace)(this.loadCache,t,n):n()}search(t=""){if(this.config.metaConfigFilePath){this.loadingMetaConfig=!0;let c=this.load(this.config.metaConfigFilePath);if(this.loadingMetaConfig=!1,c&&!c.isEmpty)return c}t=XX.default.resolve(t);let n=this.#r(t),a=n.next();if(a.done)throw new Error(`Could not find any folders to iterate through (start from ${t})`);let p=a.value,o=()=>{if((0,ACe.isDirectorySync)(p.path))for(let A of this.getSearchPlacesForDir(p,Pyr.globalConfigSearchPlacesSync))try{let m=this.#e(A);if(m!==null&&!(m.isEmpty&&this.config.ignoreEmptySearchPlaces))return this.config.transform(m)}catch(m){if(m.code==="ENOENT"||m.code==="EISDIR"||m.code==="ENOTDIR"||m.code==="EACCES")continue;throw m}let c=n.next();return c.done?this.config.transform(null):(p=c.value,this.searchCache?(0,ACe.emplace)(this.searchCache,p.path,o):o())};return this.searchCache?(0,ACe.emplace)(this.searchCache,t,o):o()}#e(t,n=[]){let a=DLi.default.readFileSync(t,"utf8");return this.toCosmiconfigResult(t,this.#t(t,a,n))}#t(t,n,a){let p=this.#i(t,n);if(!p||!(0,QLi.hasOwn)(p,"$import"))return p;let o=XX.default.dirname(t),{$import:c,...A}=p,m=Array.isArray(c)?c:[c],E=[...a,t];this.validateImports(t,m,E);let T=m.map(L=>{let P=XX.default.resolve(o,L);return this.#e(P,E)?.config});return(0,QLi.mergeAll)([...T,A],{mergeArrays:this.config.mergeImportArrays})}#i(t,n){if(n.trim()==="")return;let a=XX.default.extname(t),p=this.config.loaders[a||"noExt"]??this.config.loaders.default;if(!p)throw new Error(`No loader specified for ${(0,WLi.getExtensionDescription)(a)}`);try{let o=p(t,n);return XX.default.basename(t,a)!=="package"?o:(0,ACe.getPropertyByPath)(o,this.config.packageProp??this.config.moduleName)??null}catch(o){throw o.filepath=t,o}}#n(t){try{return DLi.default.statSync(t),!0}catch{return!1}}*#r(t){switch(this.config.searchStrategy){case"none":{yield{path:t,isGlobalConfig:!1};return}case"project":{let n=t;for(;;){yield{path:n,isGlobalConfig:!1};for(let p of["json","yaml"]){let o=XX.default.join(n,`package.${p}`);if(this.#n(o))break}let a=XX.default.dirname(n);if(a===n)break;n=a}return}case"global":yield*this.getGlobalDirs(t)}}loadSync(t){return this.load(t)}searchSync(t=""){return this.search(t)}};_ce.ExplorerSync=qyt});var ULi=ee(oy=>{"use strict";k();Object.defineProperty(oy,"__esModule",{value:!0});oy.defaultLoadersSync=oy.defaultLoaders=oy.globalConfigSearchPlacesSync=oy.globalConfigSearchPlaces=oy.getDefaultSearchPlacesSync=oy.getDefaultSearchPlaces=oy.cosmiconfigSync=oy.cosmiconfig=void 0;var DT=uQe();Object.defineProperty(oy,"defaultLoaders",{enumerable:!0,get:function(){return DT.defaultLoaders}});Object.defineProperty(oy,"defaultLoadersSync",{enumerable:!0,get:function(){return DT.defaultLoadersSync}});Object.defineProperty(oy,"getDefaultSearchPlaces",{enumerable:!0,get:function(){return DT.getDefaultSearchPlaces}});Object.defineProperty(oy,"getDefaultSearchPlacesSync",{enumerable:!0,get:function(){return DT.getDefaultSearchPlacesSync}});Object.defineProperty(oy,"globalConfigSearchPlaces",{enumerable:!0,get:function(){return DT.globalConfigSearchPlaces}});Object.defineProperty(oy,"globalConfigSearchPlacesSync",{enumerable:!0,get:function(){return DT.globalConfigSearchPlacesSync}});var Lyr=HLi(),OLi=KLi(),Jyt=dCe(),Yyt=function(t){return t};function Byr(){let t=new OLi.ExplorerSync({moduleName:"cosmiconfig",stopDir:process.cwd(),searchPlaces:DT.metaSearchPlaces,ignoreEmptySearchPlaces:!1,applyPackagePropertyPathToConfiguration:!0,loaders:DT.defaultLoaders,transform:Yyt,cache:!0,metaConfigFilePath:null,mergeImportArrays:!0,mergeSearchPlaces:!0,searchStrategy:"none"}).search();if(!t)return null;if(t.config?.loaders)throw new Error("Can not specify loaders in meta config file");if(t.config?.searchStrategy)throw new Error("Can not specify searchStrategy in meta config file");let n={mergeSearchPlaces:!0,...t.config??{}};return{config:(0,Jyt.removeUndefinedValuesFromObject)(n),filepath:t.filepath}}function xyr(e,t,n){let a=n.searchPlaces?.map(p=>p.replace("{name}",e));return n.mergeSearchPlaces?[...a??[],...t]:a??t}function GLi(e,t,n){let a=Byr();if(!a)return{...t,...(0,Jyt.removeUndefinedValuesFromObject)(n),loaders:{...t.loaders,...n.loaders}};let p=a.config,o=n.searchPlaces??t.searchPlaces;return{...t,...(0,Jyt.removeUndefinedValuesFromObject)(n),metaConfigFilePath:a.filepath,...p,searchPlaces:xyr(e,o,p),loaders:{...t.loaders,...n.loaders}}}function RLi(e){if(e.searchStrategy!=null&&e.searchStrategy!=="global"&&e.stopDir)throw new Error('Can not supply `stopDir` option with `searchStrategy` other than "global"')}function Hyr(e,t){RLi(t);let n={moduleName:e,searchPlaces:(0,DT.getDefaultSearchPlaces)(e),ignoreEmptySearchPlaces:!0,cache:!0,transform:Yyt,loaders:DT.defaultLoaders,metaConfigFilePath:null,mergeImportArrays:!0,mergeSearchPlaces:!0,searchStrategy:t.stopDir?"global":"none"};return GLi(e,n,t)}function Dyr(e,t){RLi(t);let n={moduleName:e,searchPlaces:(0,DT.getDefaultSearchPlacesSync)(e),ignoreEmptySearchPlaces:!0,cache:!0,transform:Yyt,loaders:DT.defaultLoadersSync,metaConfigFilePath:null,mergeImportArrays:!0,mergeSearchPlaces:!0,searchStrategy:t.stopDir?"global":"none"};return GLi(e,n,t)}function Wyr(e,t={}){let n=Hyr(e,t),a=new Lyr.Explorer(n);return{search:a.search.bind(a),load:a.load.bind(a),clearLoadCache:a.clearLoadCache.bind(a),clearSearchCache:a.clearSearchCache.bind(a),clearCaches:a.clearCaches.bind(a)}}oy.cosmiconfig=Wyr;function Qyr(e,t={}){let n=Dyr(e,t),a=new OLi.ExplorerSync(n);return{search:a.search.bind(a),load:a.load.bind(a),clearLoadCache:a.clearLoadCache.bind(a),clearSearchCache:a.clearSearchCache.bind(a),clearCaches:a.clearCaches.bind(a)}}oy.cosmiconfigSync=Qyr});k();k();k();var t6i=cm(wfi(),1),HF=cm(e6i(),1),UV=({accessVector:e,accessComplexity:t,attackRequirements:n,privilegesRequired:a,userInteraction:p})=>{let o=`AV:${e}/AC:${t}/PR:${a}/UI:${p}/S:${n}/VI:N/VA:N/SC:N/SI:N/SA:N`,A=new t6i.Cvss4P0(o).calculateScores().overall;return{score:A,level:YZn(A)}},YZn=e=>e>=.1&&e<=3.9?"Low":e>=4&&e<=6.9?"Medium":e>=7&&e<=8.9?"High":e>=9&&e<=10?"Critical":"Info",zae=e=>HF.default.createLogger({levels:{error:0,warn:1,info:2,http:3,verbose:4,debug:5,silly:6},format:HF.default.format.combine(HF.default.format.label({label:e}),HF.default.format.colorize(),HF.default.format.timestamp({format:()=>new Date().toLocaleString("en-US")}),HF.default.format.align(),HF.default.format.printf(t=>`\x1B[34m(${t.label})\x1B[0m \x1B[33m${t.timestamp}\x1B[0m [${t.level}]: ${t.message}`)),transports:[new HF.default.transports.Console]});k();var i6i=[{name:"X-Content-Type-Options",description:"Prevents MIME-type sniffing.",recommendation:"nosniff",check:e=>e==="nosniff"},{name:"X-Frame-Options",description:"Mitigates clickjacking attacks.",recommendation:"DENY or SAMEORIGIN",check:e=>e==="DENY"||e==="SAMEORIGIN"||e?.startsWith("ALLOW-FROM")},{name:"Strict-Transport-Security",description:"Enforces HTTPS and prevents downgrade attacks.",recommendation:"max-age=31536000; includeSubDomains; preload",check:e=>e?.includes("max-age=")&&e.includes("includeSubDomains")},{name:"Content-Security-Policy",description:"Prevents cross-site scripting (XSS) and data injection attacks.",recommendation:"script-src 'self'; object-src 'none'",check:e=>!!e},{name:"Referrer-Policy",description:"Controls how much referrer information is included with requests.",recommendation:"no-referrer or strict-origin",check:e=>["no-referrer","strict-origin","strict-origin-when-cross-origin"].includes(e??"")},{name:"Permissions-Policy",description:"Manages permissions of APIs (e.g., camera, geolocation).",recommendation:"default settings for better privacy",check:e=>!!e},{name:"Cross-Origin-Embedder-Policy",description:"Prevents a document from loading any cross-origin resources that don't explicitly grant permission.",recommendation:"require-corp",check:e=>e==="require-corp"},{name:"Cross-Origin-Opener-Policy",description:"Prevents other domains from taking control of your context via window.opener.",recommendation:"same-origin",check:e=>e==="same-origin"},{name:"Cross-Origin-Resource-Policy",description:"Prevents your resources from being used by other sites.",recommendation:"same-origin",check:e=>e==="same-origin"||e==="same-site"}],n6i=[{name:"Server",description:"Reveals server software information.",recommendation:"Remove or obfuscate this header.",check:e=>!e},{name:"X-Powered-By",description:"Reveals information about the framework (e.g., Express, PHP).",recommendation:"Remove or set to a generic value.",check:e=>!e},{name:"X-AspNet-Version",description:"Reveals ASP.NET version.",recommendation:"Remove this header.",check:e=>!e},{name:"X-AspNetMvc-Version",description:"Reveals ASP.NET MVC version.",recommendation:"Remove this header.",check:e=>!e},{name:"X-PHP-Version",description:"Reveals PHP version.",recommendation:"Disable or remove this header.",check:e=>!e},{name:"X-Generator",description:"Reveals information about CMS (e.g., WordPress, Joomla).",recommendation:"Remove this header.",check:e=>!e},{name:"X-Drupal-Dynamic-Cache",description:"Reveals Drupal cache status.",recommendation:"Remove this header.",check:e=>!e},{name:"X-Runtime",description:"Reveals the application's runtime environment.",recommendation:"Remove this header.",check:e=>!e},{name:"X-Backend-Server",description:"Leaks information about backend server infrastructure.",recommendation:"Remove or obfuscate this header.",check:e=>!e},{name:"Via",description:"Reveals intermediate proxies and gateways.",recommendation:"Remove or obfuscate this header.",check:e=>!e},{name:"X-Cache",description:"Indicates if a resource was served from cache.",recommendation:"Remove this header.",check:e=>!e},{name:"X-CF-Powered-By",description:"Reveals that the app is behind Cloudflare.",recommendation:"Remove this header.",check:e=>!e},{name:"X-Edge-IP",description:"Leaks edge server IP addresses.",recommendation:"Remove or obfuscate this header.",check:e=>!e},{name:"X-Edge-Location",description:"Reveals the physical location of edge servers.",recommendation:"Remove this header.",check:e=>!e}];var VPe=class{securityHeaders;informationalHeaders;spiderResults;logger=zae("Header Scanner");retries=3;timeout=5e3;concurrency=10;vulnerabilities=[];constructor(t){this.spiderResults=t.spiderResults,t.retries&&(this.retries=t.retries),t.timeout&&(this.timeout=t.timeout),t.concurrency&&(this.concurrency=t.concurrency),this.securityHeaders=i6i,this.informationalHeaders=n6i}withRetries=async(t,n)=>{let a;for(let p=0;p<n;p++)try{return await t()}catch(o){a=o}throw a};getHeaders=async t=>(await fetch(t)).headers;chunkArray=(t,n)=>{let a=[];for(let p=0;p<t.length;p+=n)a.push(t.slice(p,p+n));return a};checkHeaders=(t,n)=>{for(let a of this.securityHeaders)if(t.has(a.name)){let o=t.get(a.name);if(!o){let{score:A,level:m}=UV({accessVector:"N",accessComplexity:"L",attackRequirements:"N",privilegesRequired:"N",userInteraction:"N",confidentialityImpact:"N"});this.vulnerabilities.push({type:m,severity:A,url:n,description:`Header ${a.name} was not found. ${a.description} recommendation: ${a.recommendation}`});continue}if(!a.check(o)){let{score:A,level:m}=UV({accessVector:"N",accessComplexity:"L",attackRequirements:"N",privilegesRequired:"N",userInteraction:"N",confidentialityImpact:"N"});this.vulnerabilities.push({type:m,severity:A,url:n,description:`Header ${a.name} was found it had the following value ${o} it ${a.description} recommendation: ${a.recommendation}`})}}for(let a of this.informationalHeaders)if(t.has(a.name)){let o=t.get(a.name);if(!o)continue;if(!a.check(o)){let{score:A,level:m}=UV({accessVector:"N",accessComplexity:"L",attackRequirements:"N",privilegesRequired:"N",userInteraction:"N",confidentialityImpact:"N"});this.vulnerabilities.push({type:m,severity:A,url:n,description:`Header ${a.name} was found it ${a.description} recommendation: ${a.recommendation}`})}}};async scan(){let t=this.chunkArray(this.spiderResults,10);for(let n of t)await Promise.all(n.map(async a=>{try{let p=await this.withRetries(()=>this.getHeaders(a),this.retries);this.checkHeaders(p,a)}catch(p){this.logger.error(`Error scanning headers for ${a}: ${p}`)}}));return this.vulnerabilities}};k();var o6i=cm(Cgt(),1),S1t=cm(r6i(),1);var qPe=class{header={"User-Agent":new S1t.default().toString()};url;logger=zae("SpiderScanner");depth;concurrency;retries;timeout;constructor(t,n={}){let{depth:a=250,concurrency:p=5,retries:o=3,timeout:c=5e3}=n;this.depth=a,this.concurrency=p,this.retries=o,this.timeout=c;try{this.url=new URL(t),this.logger.info(`Initialized with URL: ${t}, User-Agent: ${this.header["User-Agent"]}`)}catch(A){throw A instanceof TypeError?(this.logger.error("Invalid URL"),new Error("Invalid URL")):(this.logger.error(`Unexpected error in constructor: ${A}`),A)}}normalizeDomain(t){return t.startsWith("www.")?t.slice(4):t}convertRelativeUrlToAbsolute(t){return new URL(t,this.url.toString()).toString()}isInternalLink(t){try{let n=new URL(t,this.url.href);if(!["http:","https:"].includes(n.protocol))return!1;let a=this.normalizeDomain(this.url.hostname);return this.normalizeDomain(n.hostname)===a}catch(n){return this.logger.warn(`Error parsing URL: ${t} - ${n}`),!1}}async fetchWithRetries(t,n){for(let a=1;a<=n;a++){let p=new AbortController,o=setTimeout(()=>p.abort(),this.timeout);try{this.logger.debug(`Fetching URL (Attempt ${a}): ${t}`);let c=new S1t.default().toString();this.logger.info(`Changing User-Agent to: ${c}`),this.header["User-Agent"]=c;let A=await fetch(t,{headers:this.header,signal:p.signal});if(clearTimeout(o),A.ok)return this.logger.info(`Successfully fetched URL: ${t}`),await A.text();this.logger.warn(`Failed to fetch URL (${A.status}): ${t}`)}catch(c){c.name==="AbortError"?this.logger.warn(`Fetch timed out: ${t}`):this.logger.error(`Error fetching URL: ${t} - ${c}`)}}return null}extractLinks(t){let{JSDOM:n}=o6i.default,a=new n(t),c=Array.from(a.window.document.querySelectorAll("a")).map(m=>m.href).filter(m=>this.isInternalLink(m));this.logger.debug(`Extracted ${c.length} internal links from HTML content`);let A=new RegExp(/https?:\/\/(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,6}\/(?:[^ ]*\.(?:jpg|jpeg|png|gif|css|js|svg|woff|woff2|ttf|eot|ico|mp4|webp|pdf))/);return c.map(m=>this.convertRelativeUrlToAbsolute(m)).filter(m=>!A.test(m))}async crawl(){let t=new Set,n=new Set([this.url.href]),a=new Set,p=async c=>{if(t.has(c)){this.logger.debug(`Skipping already visited URL: ${c}`);return}t.add(c),this.logger.info(`Visiting URL: ${c}`);let A=await this.fetchWithRetries(c,this.retries);if(!A)return;let m=this.extractLinks(A);for(let E of m)!t.has(E)&&n.size<this.depth&&(n.add(E),this.logger.debug(`Added to queue: ${E}`));a.add(c)},o=async()=>{let c=Array.from(n).slice(0,this.concurrency);for(let A of c)n.delete(A);await Promise.allSettled(c.map(A=>p(A)))};for(this.logger.info(`Starting crawl with depth: ${this.depth}, concurrency: ${this.concurrency}`);n.size>0&&t.size<this.depth;)await o();return this.logger.info(`Crawling completed. Total pages visited: ${a.size}`),Array.from(a)}};k();k();k();k();k();k();ase();hLe();pS();dLe();TLe();fse();WLe();QLe();KLe();hse();GLe();zLe();l_e();VLe();xLe();k();XLe();Zme();k();hse();ku();Mg();dE();var Wtr=function(e,t,n){if(t!=null){if(typeof t!="object"&&typeof t!="function")throw new TypeError("Object expected.");var a,p;if(n){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");a=t[Symbol.asyncDispose]}if(a===void 0){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");a=t[Symbol.dispose],n&&(p=a)}if(typeof a!="function")throw new TypeError("Object not disposable.");p&&(a=function(){try{p.call(this)}catch(o){return Promise.reject(o)}}),e.stack.push({value:t,dispose:a,async:n})}else n&&e.stack.push({async:!0});return t},Qtr=function(e){return function(t){function n(c){t.error=t.hasError?new e(c,t.error,"An error was suppressed during disposal."):c,t.hasError=!0}var a,p=0;function o(){for(;a=t.stack.pop();)try{if(!a.async&&p===1)return p=0,t.stack.push(a),Promise.resolve().then(o);if(a.dispose){var c=a.dispose.call(a.value);if(a.async)return p|=2,Promise.resolve(c).then(o,function(A){return n(A),o()})}else p|=1}catch(A){n(A)}if(p===1)return t.hasError?Promise.reject(t.error):Promise.resolve();if(t.hasError)throw t.error}return o()}}(typeof SuppressedError=="function"?SuppressedError:function(e,t,n){var a=new Error(n);return a.name="SuppressedError",a.error=e,a.suppressed=t,a});var iX=class{#e;#t;#i;constructor(t,n,a){this.#e=t,this.#t=n,this.#i=a}get name(){return this.#e}get initSource(){return this.#i}async run(t,n,a,p){let o=new sh;try{if(!p){let c={stack:[],error:void 0,hasError:!1};try{let m=await Wtr(c,await t.evaluateHandle((E,T)=>globalThis[E].args.get(T),this.#e,n),!1).getProperties();for(let[E,T]of m)if(E in a)switch(T.remoteObject().subtype){case"node":a[+E]=T;break;default:o.use(T)}else o.use(T)}catch(A){c.error=A,c.hasError=!0}finally{Qtr(c)}}await t.evaluate((c,A,m)=>{let E=globalThis[c].callbacks;E.get(A).resolve(m),E.delete(A)},this.#e,n,await this.#t(...a));for(let c of a)c instanceof wL&&o.use(c)}catch(c){h_(c)?await t.evaluate((A,m,E,T)=>{let L=new Error(E);L.stack=T;let P=globalThis[A].callbacks;P.get(m).reject(L),P.delete(m)},this.#e,n,c.message,c.stack).catch(Pa):await t.evaluate((A,m,E)=>{let T=globalThis[A].callbacks;T.get(m).reject(E),T.delete(m)},this.#e,n,c).catch(Pa)}}};k();ase();pS();k();ase();hLe();xd();var Ftr=function(e,t,n){if(t!=null){if(typeof t!="object"&&typeof t!="function")throw new TypeError("Object expected.");var a,p;if(n){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");a=t[Symbol.asyncDispose]}if(a===void 0){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");a=t[Symbol.dispose],n&&(p=a)}if(typeof a!="function")throw new TypeError("Object not disposable.");p&&(a=function(){try{p.call(this)}catch(o){return Promise.reject(o)}}),e.stack.push({value:t,dispose:a,async:n})}else n&&e.stack.push({async:!0});return t},Ktr=function(e){return function(t){function n(c){t.error=t.hasError?new e(c,t.error,"An error was suppressed during disposal."):c,t.hasError=!0}var a,p=0;function o(){for(;a=t.stack.pop();)try{if(!a.async&&p===1)return p=0,t.stack.push(a),Promise.resolve().then(o);if(a.dispose){var c=a.dispose.call(a.value);if(a.async)return p|=2,Promise.resolve(c).then(o,function(A){return n(A),o()})}else p|=1}catch(A){n(A)}if(p===1)return t.hasError?Promise.reject(t.error):Promise.resolve();if(t.hasError)throw t.error}return o()}}(typeof SuppressedError=="function"?SuppressedError:function(e,t,n){var a=new Error(n);return a.name="SuppressedError",a.error=e,a.suppressed=t,a}),Sse=class extends sse{#e;#t;#i;constructor(t,n,a){super(),this.#e=t,this.#t=n,this.#i=a}get id(){return this.#i}targets(){return this.#t.targets().filter(t=>t.browserContext()===this)}async pages(){return(await Promise.all(this.targets().filter(n=>n.type()==="page"||n.type()==="other"&&this.#t._getIsPageTargetCallback()?.(n)).map(n=>n.page()))).filter(n=>!!n)}async overridePermissions(t,n){let a=n.map(p=>{let o=jme.get(p);if(!o)throw new Error("Unknown permission: "+p);return o});await this.#e.send("Browser.grantPermissions",{origin:t,browserContextId:this.#i||void 0,permissions:a})}async clearPermissionOverrides(){await this.#e.send("Browser.resetPermissions",{browserContextId:this.#i||void 0})}async newPage(){let t={stack:[],error:void 0,hasError:!1};try{let n=Ftr(t,await this.waitForScreenshotOperations(),!1);return await this.#t._createPageInContext(this.#i)}catch(n){t.error=n,t.hasError=!0}finally{Ktr(t)}}browser(){return this.#t}async close(){Uo(this.#i,"Default BrowserContext cannot be closed!"),await this.#t._disposeContext(this.#i)}};k();pS();Bd();ku();xd();W3();k();l_e();ku();W3();k();pS();c_e();MA();xd();dE();var fT=class extends MH{#e;#t;#i=new nX;#n;#r;#o;constructor(t,n,a,p){super(),this.#n=t,this.#t=n,this.#e=a,this.#r=p}_setTarget(t){this.#o=t}_target(){return Uo(this.#o,"Target must exist"),this.#o}connection(){return this.#n}parentSession(){return this.#r?this.#n?.session(this.#r)??void 0:this}send(t,n,a){return this.#n?this.#n._rawSend(this.#i,t,n,this.#e,a):Promise.reject(new hC(`Protocol error (${t}): Session closed. Most likely the ${this.#t} has been closed.`))}_onMessage(t){t.id?t.error?this.#i.reject(t.id,gLe(t),t.error.message):this.#i.resolve(t.id,t.result):(Uo(!t.id),this.emit(t.method,t.params))}async detach(){if(!this.#n)throw new Error(`Session already detached. Most likely the ${this.#t} has been closed.`);await this.#n.send("Target.detachFromTarget",{sessionId:this.#e})}_onClosed(){this.#i.clear(),this.#n=void 0,this.emit(D0.Disconnected,void 0)}id(){return this.#e}getPendingProtocolErrors(){return this.#i.getPendingProtocolErrors()}};k();gT();pS();GLe();qLe();MA();Bd();k();xd();var JLe=class{#e;#t;#i=!1;constructor(t,n){this.#e=t,this.#t=n.mode!=="selectSingle"}isMultiple(){return this.#t}async accept(t){Uo(!this.#i,"Cannot accept FileChooser which is already handled!"),this.#i=!0,await this.#e.uploadFile(...t)}async cancel(){Uo(!this.#i,"Cannot cancel FileChooser which is already handled!"),this.#i=!0,await this.#e.evaluate(t=>{t.dispatchEvent(new Event("cancel",{bubbles:!0}))})}};k();var gC;(function(e){e.Request=Symbol("NetworkManager.Request"),e.RequestServedFromCache=Symbol("NetworkManager.RequestServedFromCache"),e.Response=Symbol("NetworkManager.Response"),e.RequestFailed=Symbol("NetworkManager.RequestFailed"),e.RequestFinished=Symbol("NetworkManager.RequestFinished")})(gC||(gC={}));ku();xd();W3();Mg();dE();k();pS();c_e();Zae();MA();Bd();dE();var Otr=kH("puppeteer:protocol:SEND \u25BA"),Gtr=kH("puppeteer:protocol:RECV \u25C0"),YF=class extends _s{#e;#t;#i;#n;#r=new Map;#o=!1;#a=new Set;#c=new nX;constructor(t,n,a=0,p){super(),this.#e=t,this.#i=a,this.#n=p??18e4,this.#t=n,this.#t.onmessage=this.onMessage.bind(this),this.#t.onclose=this.#s.bind(this)}static fromSession(t){return t.connection()}get delay(){return this.#i}get timeout(){return this.#n}get _closed(){return this.#o}get _sessions(){return this.#r}session(t){return this.#r.get(t)||null}url(){return this.#e}send(t,n,a){return this._rawSend(this.#c,t,n,void 0,a)}_rawSend(t,n,a,p,o){return this.#o?Promise.reject(new Error("Protocol error: Connection closed.")):t.create(n,o?.timeout??this.#n,c=>{let A=JSON.stringify({method:n,params:a,id:c,sessionId:p});Otr(A),this.#t.send(A)})}async closeBrowser(){await this.send("Browser.close")}async onMessage(t){this.#i&&await new Promise(a=>setTimeout(a,this.#i)),Gtr(t);let n=JSON.parse(t);if(n.method==="Target.attachedToTarget"){let a=n.params.sessionId,p=new fT(this,n.params.targetInfo.type,a,n.sessionId);this.#r.set(a,p),this.emit(D0.SessionAttached,p);let o=this.#r.get(n.sessionId);o&&o.emit(D0.SessionAttached,p)}else if(n.method==="Target.detachedFromTarget"){let a=this.#r.get(n.params.sessionId);if(a){a._onClosed(),this.#r.delete(n.params.sessionId),this.emit(D0.SessionDetached,a);let p=this.#r.get(n.sessionId);p&&p.emit(D0.SessionDetached,a)}}if(n.sessionId){let a=this.#r.get(n.sessionId);a&&a._onMessage(n)}else n.id?n.error?this.#c.reject(n.id,gLe(n),n.error.message):this.#c.resolve(n.id,n.result):this.emit(n.method,n.params)}#s(){if(!this.#o){this.#o=!0,this.#t.onmessage=void 0,this.#t.onclose=void 0,this.#c.clear();for(let t of this.#r.values())t._onClosed();this.#r.clear(),this.emit(D0.Disconnected,void 0)}}dispose(){this.#s(),this.#t.close()}isAutoAttached(t){return!this.#a.has(t)}async _createSession(t,n=!0){n||this.#a.add(t.targetId);let{sessionId:a}=await this.send("Target.attachToTarget",{targetId:t.targetId,flatten:!0});this.#a.delete(t.targetId);let p=this.#r.get(a);if(!p)throw new Error("CDPSession creation failed.");return p}async createSession(t){return await this._createSession(t,!1)}getPendingProtocolErrors(){let t=[];t.push(...this.#c.getPendingProtocolErrors());for(let n of this.#r.values())t.push(...n.getPendingProtocolErrors());return t}};function p_e(e){return e instanceof hC}YLe();k();dLe();var jLe=class extends lse{#e;constructor(t,n,a,p=""){super(n,a,p),this.#e=t}async handle(t){await this.#e.send("Page.handleJavaScriptDialog",{accept:t.accept,promptText:t.text})}};ZLe();k();pS();Bd();xd();W3();var rX=class extends _s{#e;#t=new Map;#i=new Map;#n=new Map;#r;#o;#a=new WeakMap;#c=qu.create();#s=new Set;constructor(t,n,a){super(),this.#e=t,this.#r=a,this.#o=n,this.#e.on("Target.targetCreated",this.#l),this.#e.on("Target.targetDestroyed",this.#u),this.#e.on(D0.SessionDetached,this.#p),this.setupAttachmentListeners(this.#e)}setupAttachmentListeners(t){let n=a=>this.#h(t,a);Uo(!this.#a.has(t)),this.#a.set(t,n),t.on("Target.attachedToTarget",n)}#p=t=>{this.removeSessionListeners(t),this.#n.delete(t.id())};removeSessionListeners(t){this.#a.has(t)&&(t.off("Target.attachedToTarget",this.#a.get(t)),this.#a.delete(t))}getAvailableTargets(){return this.#i}getChildTargets(t){return new Set}dispose(){this.#e.off("Target.targetCreated",this.#l),this.#e.off("Target.targetDestroyed",this.#u)}async initialize(){await this.#e.send("Target.setDiscoverTargets",{discover:!0,filter:[{}]}),this.#s=new Set(this.#t.keys()),await this.#c.valueOrThrow()}#l=async t=>{if(this.#t.has(t.targetInfo.targetId))return;if(this.#t.set(t.targetInfo.targetId,t.targetInfo),t.targetInfo.type==="browser"&&t.targetInfo.attached){let a=this.#o(t.targetInfo,void 0);a._initialize(),this.#i.set(t.targetInfo.targetId,a),this.#d(a._targetId);return}let n=this.#o(t.targetInfo,void 0);if(this.#r&&!this.#r(n)){this.#d(t.targetInfo.targetId);return}n._initialize(),this.#i.set(t.targetInfo.targetId,n),this.emit("targetAvailable",n),this.#d(n._targetId)};#u=t=>{this.#t.delete(t.targetId),this.#d(t.targetId);let n=this.#i.get(t.targetId);n&&(this.emit("targetGone",n),this.#i.delete(t.targetId))};#h=async(t,n)=>{let a=n.targetInfo,p=this.#e.session(n.sessionId);if(!p)throw new Error(`Session ${n.sessionId} was not created.`);let o=this.#i.get(a.targetId);Uo(o,`Target ${a.targetId} is missing`),p._setTarget(o),this.setupAttachmentListeners(p),this.#n.set(p.id(),this.#i.get(a.targetId)),t.emit(D0.Ready,p)};#d(t){this.#s.delete(t),this.#s.size===0&&this.#c.resolve()}};k();pS();fse();Bd();ku();xd();W3();Mg();dE();k();var eBe=class{#e;#t;#i=new WeakMap;constructor(t,n,a){this.#e=n,this.#t=a,this.#i.set(t,n)}get id(){return this.#e}get source(){return this.#t}getIdForFrame(t){return this.#i.get(t)}setIdForFrame(t,n){this.#i.set(t,n)}};k();xd();W3();var dft=class{id;name;constructor(t,n){this.id=t,this.name=n}},gft=class{#e;#t;#i;#n=!1;#r=this.#a.bind(this);#o=new Set;devices=[];constructor(t,n,a){this.#e=t,this.#t=n,this.#i=a.id,this.#e.on("DeviceAccess.deviceRequestPrompted",this.#r),this.#e.on("Target.detachedFromTarget",()=>{this.#e=null}),this.#a(a)}#a(t){if(t.id===this.#i)for(let n of t.devices){if(this.devices.some(p=>p.id===n.id))continue;let a=new dft(n.id,n.name);this.devices.push(a);for(let p of this.#o)p.filter(a)&&p.promise.resolve(a)}}async waitForDevice(t,n={}){for(let c of this.devices)if(t(c))return c;let{timeout:a=this.#t.timeout()}=n,p=qu.create({message:`Waiting for \`DeviceRequestPromptDevice\` failed: ${a}ms exceeded`,timeout:a});n.signal&&n.signal.addEventListener("abort",()=>{p.reject(n.signal?.reason)},{once:!0});let o={filter:t,promise:p};this.#o.add(o);try{return await p.valueOrThrow()}finally{this.#o.delete(o)}}async select(t){return Uo(this.#e!==null,"Cannot select device through detached session!"),Uo(this.devices.includes(t),"Cannot select unknown device!"),Uo(!this.#n,"Cannot select DeviceRequestPrompt which is already handled!"),this.#e.off("DeviceAccess.deviceRequestPrompted",this.#r),this.#n=!0,await this.#e.send("DeviceAccess.selectPrompt",{id:this.#i,deviceId:t.id})}async cancel(){return Uo(this.#e!==null,"Cannot cancel prompt through detached session!"),Uo(!this.#n,"Cannot cancel DeviceRequestPrompt which is already handled!"),this.#e.off("DeviceAccess.deviceRequestPrompted",this.#r),this.#n=!0,await this.#e.send("DeviceAccess.cancelPrompt",{id:this.#i})}},tBe=class{#e;#t;#i=new Set;constructor(t,n){this.#e=t,this.#t=n,this.#e.on("DeviceAccess.deviceRequestPrompted",a=>{this.#n(a)}),this.#e.on("Target.detachedFromTarget",()=>{this.#e=null})}async waitForDevicePrompt(t={}){Uo(this.#e!==null,"Cannot wait for device prompt through detached session!");let n=this.#i.size===0,a;n&&(a=this.#e.send("DeviceAccess.enable"));let{timeout:p=this.#t.timeout()}=t,o=qu.create({message:`Waiting for \`DeviceRequestPrompt\` failed: ${p}ms exceeded`,timeout:p});t.signal&&t.signal.addEventListener("abort",()=>{o.reject(t.signal?.reason)},{once:!0}),this.#i.add(o);try{let[c]=await Promise.all([o.valueOrThrow(),a]);return c}finally{this.#i.delete(o)}}#n(t){if(!this.#i.size)return;Uo(this.#e!==null);let n=new gft(this.#e,this.#t,t);for(let a of this.#i)a.resolve(n);this.#i.clear()}};k();pS();Bd();Q$();t_e();ku();JV();Mg();W$();$me();Zme();k();TLe();ku();UF();xd();JV();dC();k();hse();ku();k();ku();xd();function Aft(e){let t,n;if(!e.exception)t="Error",n=e.text;else{if((e.exception.type!=="object"||e.exception.subtype!=="error")&&!e.exception.objectId)return BH(e.exception);{let A=uwi(e);t=A.name,n=A.message}}let a=n.split(`
|
1424
|
+
`)} (same as ${A+1}.)`)}}getSearchPlacesForDir(t,n){return(t.isGlobalConfig?n:this.config.searchPlaces).map(a=>fce.default.join(t.path,a))}getGlobalConfigDir(){return(0,Syr.default)(this.config.moduleName,{suffix:""}).config}*getGlobalDirs(t){let n=fce.default.resolve(this.config.stopDir??byr.default.homedir());yield{path:t,isGlobalConfig:!1};let a=t;for(;a!==n;){let p=fce.default.dirname(a);if(p===a)break;yield{path:p,isGlobalConfig:!1},a=p}yield{path:this.getGlobalConfigDir(),isGlobalConfig:!0}}};zX.ExplorerBase=Gyt;function Ryt(e){return e?`extension "${e}"`:"files without extensions"}zX.getExtensionDescription=Ryt});var Vyt=ee(KZ=>{"use strict";k();Object.defineProperty(KZ,"__esModule",{value:!0});KZ.mergeAll=KZ.hasOwn=void 0;KZ.hasOwn=Function.prototype.call.bind(Object.prototype.hasOwnProperty);var Myr=Function.prototype.call.bind(Object.prototype.toString);function TLi(e){return Myr(e)==="[object Object]"}function NLi(e,t,n){for(let a of Object.keys(t)){let p=t[a];if((0,KZ.hasOwn)(e,a)){if(Array.isArray(e[a])&&Array.isArray(p)){if(n.mergeArrays){e[a].push(...p);continue}}else if(TLi(e[a])&&TLi(p)){e[a]=NLi(e[a],p,n);continue}}e[a]=p}return e}function Tyr(e,t){return e.reduce((n,a)=>NLi(n,a,t),{})}KZ.mergeAll=Tyr});var HLi=ee(mce=>{"use strict";k();var xLi=mce&&mce.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(mce,"__esModule",{value:!0});mce.Explorer=void 0;var PLi=xLi(gn("fs/promises")),VX=xLi(gn("path")),Nyr=uQe(),LLi=zyt(),BLi=Vyt(),gCe=dCe(),Xyt=class extends LLi.ExplorerBase{async load(t){t=VX.default.resolve(t);let n=async()=>await this.config.transform(await this.#e(t));return this.loadCache?await(0,gCe.emplace)(this.loadCache,t,n):await n()}async search(t=""){if(this.config.metaConfigFilePath){this.loadingMetaConfig=!0;let c=await this.load(this.config.metaConfigFilePath);if(this.loadingMetaConfig=!1,c&&!c.isEmpty)return c}t=VX.default.resolve(t);let n=this.#r(t),a=await n.next();if(a.done)throw new Error(`Could not find any folders to iterate through (start from ${t})`);let p=a.value,o=async()=>{if(await(0,gCe.isDirectory)(p.path))for(let A of this.getSearchPlacesForDir(p,Nyr.globalConfigSearchPlaces))try{let m=await this.#e(A);if(m!==null&&!(m.isEmpty&&this.config.ignoreEmptySearchPlaces))return await this.config.transform(m)}catch(m){if(m.code==="ENOENT"||m.code==="EISDIR"||m.code==="ENOTDIR"||m.code==="EACCES")continue;throw m}let c=await n.next();return c.done?await this.config.transform(null):(p=c.value,this.searchCache?await(0,gCe.emplace)(this.searchCache,p.path,o):await o())};return this.searchCache?await(0,gCe.emplace)(this.searchCache,t,o):await o()}async#e(t,n=[]){let a=await PLi.default.readFile(t,{encoding:"utf-8"});return this.toCosmiconfigResult(t,await this.#t(t,a,n))}async#t(t,n,a){let p=await this.#i(t,n);if(!p||!(0,BLi.hasOwn)(p,"$import"))return p;let o=VX.default.dirname(t),{$import:c,...A}=p,m=Array.isArray(c)?c:[c],E=[...a,t];this.validateImports(t,m,E);let T=await Promise.all(m.map(async L=>{let P=VX.default.resolve(o,L);return(await this.#e(P,E))?.config}));return(0,BLi.mergeAll)([...T,A],{mergeArrays:this.config.mergeImportArrays})}async#i(t,n){if(n.trim()==="")return;let a=VX.default.extname(t),p=this.config.loaders[a||"noExt"]??this.config.loaders.default;if(!p)throw new Error(`No loader specified for ${(0,LLi.getExtensionDescription)(a)}`);try{let o=await p(t,n);return VX.default.basename(t,a)!=="package"?o:(0,gCe.getPropertyByPath)(o,this.config.packageProp??this.config.moduleName)??null}catch(o){throw o.filepath=t,o}}async#n(t){try{return await PLi.default.stat(t),!0}catch{return!1}}async*#r(t){switch(this.config.searchStrategy){case"none":{yield{path:t,isGlobalConfig:!1};return}case"project":{let n=t;for(;;){yield{path:n,isGlobalConfig:!1};for(let p of["json","yaml"]){let o=VX.default.join(n,`package.${p}`);if(await this.#n(o))break}let a=VX.default.dirname(n);if(a===n)break;n=a}return}case"global":yield*this.getGlobalDirs(t)}}};mce.Explorer=Xyt});var KLi=ee(_ce=>{"use strict";k();var FLi=_ce&&_ce.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(_ce,"__esModule",{value:!0});_ce.ExplorerSync=void 0;var DLi=FLi(gn("fs")),XX=FLi(gn("path")),Pyr=uQe(),WLi=zyt(),QLi=Vyt(),ACe=dCe(),qyt=class extends WLi.ExplorerBase{load(t){t=XX.default.resolve(t);let n=()=>this.config.transform(this.#e(t));return this.loadCache?(0,ACe.emplace)(this.loadCache,t,n):n()}search(t=""){if(this.config.metaConfigFilePath){this.loadingMetaConfig=!0;let c=this.load(this.config.metaConfigFilePath);if(this.loadingMetaConfig=!1,c&&!c.isEmpty)return c}t=XX.default.resolve(t);let n=this.#r(t),a=n.next();if(a.done)throw new Error(`Could not find any folders to iterate through (start from ${t})`);let p=a.value,o=()=>{if((0,ACe.isDirectorySync)(p.path))for(let A of this.getSearchPlacesForDir(p,Pyr.globalConfigSearchPlacesSync))try{let m=this.#e(A);if(m!==null&&!(m.isEmpty&&this.config.ignoreEmptySearchPlaces))return this.config.transform(m)}catch(m){if(m.code==="ENOENT"||m.code==="EISDIR"||m.code==="ENOTDIR"||m.code==="EACCES")continue;throw m}let c=n.next();return c.done?this.config.transform(null):(p=c.value,this.searchCache?(0,ACe.emplace)(this.searchCache,p.path,o):o())};return this.searchCache?(0,ACe.emplace)(this.searchCache,t,o):o()}#e(t,n=[]){let a=DLi.default.readFileSync(t,"utf8");return this.toCosmiconfigResult(t,this.#t(t,a,n))}#t(t,n,a){let p=this.#i(t,n);if(!p||!(0,QLi.hasOwn)(p,"$import"))return p;let o=XX.default.dirname(t),{$import:c,...A}=p,m=Array.isArray(c)?c:[c],E=[...a,t];this.validateImports(t,m,E);let T=m.map(L=>{let P=XX.default.resolve(o,L);return this.#e(P,E)?.config});return(0,QLi.mergeAll)([...T,A],{mergeArrays:this.config.mergeImportArrays})}#i(t,n){if(n.trim()==="")return;let a=XX.default.extname(t),p=this.config.loaders[a||"noExt"]??this.config.loaders.default;if(!p)throw new Error(`No loader specified for ${(0,WLi.getExtensionDescription)(a)}`);try{let o=p(t,n);return XX.default.basename(t,a)!=="package"?o:(0,ACe.getPropertyByPath)(o,this.config.packageProp??this.config.moduleName)??null}catch(o){throw o.filepath=t,o}}#n(t){try{return DLi.default.statSync(t),!0}catch{return!1}}*#r(t){switch(this.config.searchStrategy){case"none":{yield{path:t,isGlobalConfig:!1};return}case"project":{let n=t;for(;;){yield{path:n,isGlobalConfig:!1};for(let p of["json","yaml"]){let o=XX.default.join(n,`package.${p}`);if(this.#n(o))break}let a=XX.default.dirname(n);if(a===n)break;n=a}return}case"global":yield*this.getGlobalDirs(t)}}loadSync(t){return this.load(t)}searchSync(t=""){return this.search(t)}};_ce.ExplorerSync=qyt});var ULi=ee(oy=>{"use strict";k();Object.defineProperty(oy,"__esModule",{value:!0});oy.defaultLoadersSync=oy.defaultLoaders=oy.globalConfigSearchPlacesSync=oy.globalConfigSearchPlaces=oy.getDefaultSearchPlacesSync=oy.getDefaultSearchPlaces=oy.cosmiconfigSync=oy.cosmiconfig=void 0;var DT=uQe();Object.defineProperty(oy,"defaultLoaders",{enumerable:!0,get:function(){return DT.defaultLoaders}});Object.defineProperty(oy,"defaultLoadersSync",{enumerable:!0,get:function(){return DT.defaultLoadersSync}});Object.defineProperty(oy,"getDefaultSearchPlaces",{enumerable:!0,get:function(){return DT.getDefaultSearchPlaces}});Object.defineProperty(oy,"getDefaultSearchPlacesSync",{enumerable:!0,get:function(){return DT.getDefaultSearchPlacesSync}});Object.defineProperty(oy,"globalConfigSearchPlaces",{enumerable:!0,get:function(){return DT.globalConfigSearchPlaces}});Object.defineProperty(oy,"globalConfigSearchPlacesSync",{enumerable:!0,get:function(){return DT.globalConfigSearchPlacesSync}});var Lyr=HLi(),OLi=KLi(),Jyt=dCe(),Yyt=function(t){return t};function Byr(){let t=new OLi.ExplorerSync({moduleName:"cosmiconfig",stopDir:process.cwd(),searchPlaces:DT.metaSearchPlaces,ignoreEmptySearchPlaces:!1,applyPackagePropertyPathToConfiguration:!0,loaders:DT.defaultLoaders,transform:Yyt,cache:!0,metaConfigFilePath:null,mergeImportArrays:!0,mergeSearchPlaces:!0,searchStrategy:"none"}).search();if(!t)return null;if(t.config?.loaders)throw new Error("Can not specify loaders in meta config file");if(t.config?.searchStrategy)throw new Error("Can not specify searchStrategy in meta config file");let n={mergeSearchPlaces:!0,...t.config??{}};return{config:(0,Jyt.removeUndefinedValuesFromObject)(n),filepath:t.filepath}}function xyr(e,t,n){let a=n.searchPlaces?.map(p=>p.replace("{name}",e));return n.mergeSearchPlaces?[...a??[],...t]:a??t}function GLi(e,t,n){let a=Byr();if(!a)return{...t,...(0,Jyt.removeUndefinedValuesFromObject)(n),loaders:{...t.loaders,...n.loaders}};let p=a.config,o=n.searchPlaces??t.searchPlaces;return{...t,...(0,Jyt.removeUndefinedValuesFromObject)(n),metaConfigFilePath:a.filepath,...p,searchPlaces:xyr(e,o,p),loaders:{...t.loaders,...n.loaders}}}function RLi(e){if(e.searchStrategy!=null&&e.searchStrategy!=="global"&&e.stopDir)throw new Error('Can not supply `stopDir` option with `searchStrategy` other than "global"')}function Hyr(e,t){RLi(t);let n={moduleName:e,searchPlaces:(0,DT.getDefaultSearchPlaces)(e),ignoreEmptySearchPlaces:!0,cache:!0,transform:Yyt,loaders:DT.defaultLoaders,metaConfigFilePath:null,mergeImportArrays:!0,mergeSearchPlaces:!0,searchStrategy:t.stopDir?"global":"none"};return GLi(e,n,t)}function Dyr(e,t){RLi(t);let n={moduleName:e,searchPlaces:(0,DT.getDefaultSearchPlacesSync)(e),ignoreEmptySearchPlaces:!0,cache:!0,transform:Yyt,loaders:DT.defaultLoadersSync,metaConfigFilePath:null,mergeImportArrays:!0,mergeSearchPlaces:!0,searchStrategy:t.stopDir?"global":"none"};return GLi(e,n,t)}function Wyr(e,t={}){let n=Hyr(e,t),a=new Lyr.Explorer(n);return{search:a.search.bind(a),load:a.load.bind(a),clearLoadCache:a.clearLoadCache.bind(a),clearSearchCache:a.clearSearchCache.bind(a),clearCaches:a.clearCaches.bind(a)}}oy.cosmiconfig=Wyr;function Qyr(e,t={}){let n=Dyr(e,t),a=new OLi.ExplorerSync(n);return{search:a.search.bind(a),load:a.load.bind(a),clearLoadCache:a.clearLoadCache.bind(a),clearSearchCache:a.clearSearchCache.bind(a),clearCaches:a.clearCaches.bind(a)}}oy.cosmiconfigSync=Qyr});k();k();k();var t6i=cm(wfi(),1),HF=cm(e6i(),1),UV=({accessVector:e,accessComplexity:t,attackRequirements:n,privilegesRequired:a,userInteraction:p})=>{let o=`AV:${e}/AC:${t}/PR:${a}/UI:${p}/S:${n}/VI:N/VA:N/SC:N/SI:N/SA:N`,A=new t6i.Cvss4P0(o).calculateScores().overall;return{score:A,level:YZn(A)}},YZn=e=>e>=.1&&e<=3.9?"Low":e>=4&&e<=6.9?"Medium":e>=7&&e<=8.9?"High":e>=9&&e<=10?"Critical":"Info",zae=e=>HF.default.createLogger({level:"silly",levels:{error:0,warn:1,info:2,http:3,verbose:4,debug:5,silly:6},format:HF.default.format.combine(HF.default.format.label({label:e}),HF.default.format.colorize(),HF.default.format.timestamp({format:()=>new Date().toLocaleString("en-US")}),HF.default.format.align(),HF.default.format.printf(t=>`\x1B[34m(${t.label})\x1B[0m \x1B[33m${t.timestamp}\x1B[0m [${t.level}]: ${t.message}`)),transports:[new HF.default.transports.Console]});k();var i6i=[{name:"X-Content-Type-Options",description:"Prevents MIME-type sniffing.",recommendation:"nosniff",check:e=>e==="nosniff"},{name:"X-Frame-Options",description:"Mitigates clickjacking attacks.",recommendation:"DENY or SAMEORIGIN",check:e=>e==="DENY"||e==="SAMEORIGIN"||e?.startsWith("ALLOW-FROM")},{name:"Strict-Transport-Security",description:"Enforces HTTPS and prevents downgrade attacks.",recommendation:"max-age=31536000; includeSubDomains; preload",check:e=>e?.includes("max-age=")&&e.includes("includeSubDomains")},{name:"Content-Security-Policy",description:"Prevents cross-site scripting (XSS) and data injection attacks.",recommendation:"script-src 'self'; object-src 'none'",check:e=>!!e},{name:"Referrer-Policy",description:"Controls how much referrer information is included with requests.",recommendation:"no-referrer or strict-origin",check:e=>["no-referrer","strict-origin","strict-origin-when-cross-origin"].includes(e??"")},{name:"Permissions-Policy",description:"Manages permissions of APIs (e.g., camera, geolocation).",recommendation:"default settings for better privacy",check:e=>!!e},{name:"Cross-Origin-Embedder-Policy",description:"Prevents a document from loading any cross-origin resources that don't explicitly grant permission.",recommendation:"require-corp",check:e=>e==="require-corp"},{name:"Cross-Origin-Opener-Policy",description:"Prevents other domains from taking control of your context via window.opener.",recommendation:"same-origin",check:e=>e==="same-origin"},{name:"Cross-Origin-Resource-Policy",description:"Prevents your resources from being used by other sites.",recommendation:"same-origin",check:e=>e==="same-origin"||e==="same-site"}],n6i=[{name:"Server",description:"Reveals server software information.",recommendation:"Remove or obfuscate this header.",check:e=>!e},{name:"X-Powered-By",description:"Reveals information about the framework (e.g., Express, PHP).",recommendation:"Remove or set to a generic value.",check:e=>!e},{name:"X-AspNet-Version",description:"Reveals ASP.NET version.",recommendation:"Remove this header.",check:e=>!e},{name:"X-AspNetMvc-Version",description:"Reveals ASP.NET MVC version.",recommendation:"Remove this header.",check:e=>!e},{name:"X-PHP-Version",description:"Reveals PHP version.",recommendation:"Disable or remove this header.",check:e=>!e},{name:"X-Generator",description:"Reveals information about CMS (e.g., WordPress, Joomla).",recommendation:"Remove this header.",check:e=>!e},{name:"X-Drupal-Dynamic-Cache",description:"Reveals Drupal cache status.",recommendation:"Remove this header.",check:e=>!e},{name:"X-Runtime",description:"Reveals the application's runtime environment.",recommendation:"Remove this header.",check:e=>!e},{name:"X-Backend-Server",description:"Leaks information about backend server infrastructure.",recommendation:"Remove or obfuscate this header.",check:e=>!e},{name:"Via",description:"Reveals intermediate proxies and gateways.",recommendation:"Remove or obfuscate this header.",check:e=>!e},{name:"X-Cache",description:"Indicates if a resource was served from cache.",recommendation:"Remove this header.",check:e=>!e},{name:"X-CF-Powered-By",description:"Reveals that the app is behind Cloudflare.",recommendation:"Remove this header.",check:e=>!e},{name:"X-Edge-IP",description:"Leaks edge server IP addresses.",recommendation:"Remove or obfuscate this header.",check:e=>!e},{name:"X-Edge-Location",description:"Reveals the physical location of edge servers.",recommendation:"Remove this header.",check:e=>!e}];var VPe=class{securityHeaders;informationalHeaders;spiderResults;logger=zae("Header Scanner");retries=3;timeout=5e3;concurrency=10;vulnerabilities=[];constructor(t){this.spiderResults=t.spiderResults,t.retries&&(this.retries=t.retries),t.timeout&&(this.timeout=t.timeout),t.concurrency&&(this.concurrency=t.concurrency),this.securityHeaders=i6i,this.informationalHeaders=n6i}withRetries=async(t,n)=>{let a;for(let p=0;p<n;p++)try{return await t()}catch(o){a=o}throw a};getHeaders=async t=>(await fetch(t)).headers;chunkArray=(t,n)=>{let a=[];for(let p=0;p<t.length;p+=n)a.push(t.slice(p,p+n));return a};checkHeaders=(t,n)=>{for(let a of this.securityHeaders)if(t.has(a.name)){let o=t.get(a.name);if(!o){let{score:A,level:m}=UV({accessVector:"N",accessComplexity:"L",attackRequirements:"N",privilegesRequired:"N",userInteraction:"N",confidentialityImpact:"N"});this.vulnerabilities.push({type:m,severity:A,url:n,description:`Header ${a.name} was not found. ${a.description} recommendation: ${a.recommendation}`});continue}if(!a.check(o)){let{score:A,level:m}=UV({accessVector:"N",accessComplexity:"L",attackRequirements:"N",privilegesRequired:"N",userInteraction:"N",confidentialityImpact:"N"});this.vulnerabilities.push({type:m,severity:A,url:n,description:`Header ${a.name} was found it had the following value ${o} it ${a.description} recommendation: ${a.recommendation}`})}}for(let a of this.informationalHeaders)if(t.has(a.name)){let o=t.get(a.name);if(!o)continue;if(!a.check(o)){let{score:A,level:m}=UV({accessVector:"N",accessComplexity:"L",attackRequirements:"N",privilegesRequired:"N",userInteraction:"N",confidentialityImpact:"N"});this.vulnerabilities.push({type:m,severity:A,url:n,description:`Header ${a.name} was found it ${a.description} recommendation: ${a.recommendation}`})}}};async scan(){let t=this.chunkArray(this.spiderResults,10);for(let n of t)await Promise.all(n.map(async a=>{try{let p=await this.withRetries(()=>this.getHeaders(a),this.retries);this.checkHeaders(p,a)}catch(p){this.logger.error(`Error scanning headers for ${a}: ${p}`)}}));return this.vulnerabilities}};k();var o6i=cm(Cgt(),1),S1t=cm(r6i(),1);var qPe=class{header={"User-Agent":new S1t.default().toString()};url;logger=zae("SpiderScanner");depth;concurrency;retries;timeout;constructor(t,n={}){let{depth:a=250,concurrency:p=5,retries:o=3,timeout:c=5e3}=n;this.depth=a,this.concurrency=p,this.retries=o,this.timeout=c;try{this.url=new URL(t),this.logger.info(`Initialized with URL: ${t}, User-Agent: ${this.header["User-Agent"]}`)}catch(A){throw A instanceof TypeError?(this.logger.error("Invalid URL"),new Error("Invalid URL")):(this.logger.error(`Unexpected error in constructor: ${A}`),A)}}normalizeDomain(t){return t.startsWith("www.")?t.slice(4):t}convertRelativeUrlToAbsolute(t){return new URL(t,this.url.toString()).toString()}isInternalLink(t){try{let n=new URL(t,this.url.href);if(!["http:","https:"].includes(n.protocol))return!1;let a=this.normalizeDomain(this.url.hostname);return this.normalizeDomain(n.hostname)===a}catch(n){return this.logger.warn(`Error parsing URL: ${t} - ${n}`),!1}}async fetchWithRetries(t,n){for(let a=1;a<=n;a++){let p=new AbortController,o=setTimeout(()=>p.abort(),this.timeout);try{this.logger.debug(`Fetching URL (Attempt ${a}): ${t}`);let c=new S1t.default().toString();this.logger.info(`Changing User-Agent to: ${c}`),this.header["User-Agent"]=c;let A=await fetch(t,{headers:this.header,signal:p.signal});if(clearTimeout(o),A.ok)return this.logger.info(`Successfully fetched URL: ${t}`),await A.text();this.logger.warn(`Failed to fetch URL (${A.status}): ${t}`)}catch(c){c.name==="AbortError"?this.logger.warn(`Fetch timed out: ${t}`):this.logger.error(`Error fetching URL: ${t} - ${c}`)}}return null}extractLinks(t){let{JSDOM:n}=o6i.default,a=new n(t),c=Array.from(a.window.document.querySelectorAll("a")).map(m=>m.href).filter(m=>this.isInternalLink(m));this.logger.debug(`Extracted ${c.length} internal links from HTML content`);let A=new RegExp(/https?:\/\/(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,6}\/(?:[^ ]*\.(?:jpg|jpeg|png|gif|css|js|svg|woff|woff2|ttf|eot|ico|mp4|webp|pdf))/);return c.map(m=>this.convertRelativeUrlToAbsolute(m)).filter(m=>!A.test(m))}async crawl(){let t=new Set,n=new Set([this.url.href]),a=new Set,p=async c=>{if(t.has(c)){this.logger.debug(`Skipping already visited URL: ${c}`);return}t.add(c),this.logger.info(`Visiting URL: ${c}`);let A=await this.fetchWithRetries(c,this.retries);if(!A)return;let m=this.extractLinks(A);for(let E of m)!t.has(E)&&n.size<this.depth&&(n.add(E),this.logger.debug(`Added to queue: ${E}`));a.add(c)},o=async()=>{let c=Array.from(n).slice(0,this.concurrency);for(let A of c)n.delete(A);await Promise.allSettled(c.map(A=>p(A)))};for(this.logger.info(`Starting crawl with depth: ${this.depth}, concurrency: ${this.concurrency}`);n.size>0&&t.size<this.depth;)await o();return this.logger.info(`Crawling completed. Total pages visited: ${a.size}`),Array.from(a)}};k();k();k();k();k();k();ase();hLe();pS();dLe();TLe();fse();WLe();QLe();KLe();hse();GLe();zLe();l_e();VLe();xLe();k();XLe();Zme();k();hse();ku();Mg();dE();var Wtr=function(e,t,n){if(t!=null){if(typeof t!="object"&&typeof t!="function")throw new TypeError("Object expected.");var a,p;if(n){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");a=t[Symbol.asyncDispose]}if(a===void 0){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");a=t[Symbol.dispose],n&&(p=a)}if(typeof a!="function")throw new TypeError("Object not disposable.");p&&(a=function(){try{p.call(this)}catch(o){return Promise.reject(o)}}),e.stack.push({value:t,dispose:a,async:n})}else n&&e.stack.push({async:!0});return t},Qtr=function(e){return function(t){function n(c){t.error=t.hasError?new e(c,t.error,"An error was suppressed during disposal."):c,t.hasError=!0}var a,p=0;function o(){for(;a=t.stack.pop();)try{if(!a.async&&p===1)return p=0,t.stack.push(a),Promise.resolve().then(o);if(a.dispose){var c=a.dispose.call(a.value);if(a.async)return p|=2,Promise.resolve(c).then(o,function(A){return n(A),o()})}else p|=1}catch(A){n(A)}if(p===1)return t.hasError?Promise.reject(t.error):Promise.resolve();if(t.hasError)throw t.error}return o()}}(typeof SuppressedError=="function"?SuppressedError:function(e,t,n){var a=new Error(n);return a.name="SuppressedError",a.error=e,a.suppressed=t,a});var iX=class{#e;#t;#i;constructor(t,n,a){this.#e=t,this.#t=n,this.#i=a}get name(){return this.#e}get initSource(){return this.#i}async run(t,n,a,p){let o=new sh;try{if(!p){let c={stack:[],error:void 0,hasError:!1};try{let m=await Wtr(c,await t.evaluateHandle((E,T)=>globalThis[E].args.get(T),this.#e,n),!1).getProperties();for(let[E,T]of m)if(E in a)switch(T.remoteObject().subtype){case"node":a[+E]=T;break;default:o.use(T)}else o.use(T)}catch(A){c.error=A,c.hasError=!0}finally{Qtr(c)}}await t.evaluate((c,A,m)=>{let E=globalThis[c].callbacks;E.get(A).resolve(m),E.delete(A)},this.#e,n,await this.#t(...a));for(let c of a)c instanceof wL&&o.use(c)}catch(c){h_(c)?await t.evaluate((A,m,E,T)=>{let L=new Error(E);L.stack=T;let P=globalThis[A].callbacks;P.get(m).reject(L),P.delete(m)},this.#e,n,c.message,c.stack).catch(Pa):await t.evaluate((A,m,E)=>{let T=globalThis[A].callbacks;T.get(m).reject(E),T.delete(m)},this.#e,n,c).catch(Pa)}}};k();ase();pS();k();ase();hLe();xd();var Ftr=function(e,t,n){if(t!=null){if(typeof t!="object"&&typeof t!="function")throw new TypeError("Object expected.");var a,p;if(n){if(!Symbol.asyncDispose)throw new TypeError("Symbol.asyncDispose is not defined.");a=t[Symbol.asyncDispose]}if(a===void 0){if(!Symbol.dispose)throw new TypeError("Symbol.dispose is not defined.");a=t[Symbol.dispose],n&&(p=a)}if(typeof a!="function")throw new TypeError("Object not disposable.");p&&(a=function(){try{p.call(this)}catch(o){return Promise.reject(o)}}),e.stack.push({value:t,dispose:a,async:n})}else n&&e.stack.push({async:!0});return t},Ktr=function(e){return function(t){function n(c){t.error=t.hasError?new e(c,t.error,"An error was suppressed during disposal."):c,t.hasError=!0}var a,p=0;function o(){for(;a=t.stack.pop();)try{if(!a.async&&p===1)return p=0,t.stack.push(a),Promise.resolve().then(o);if(a.dispose){var c=a.dispose.call(a.value);if(a.async)return p|=2,Promise.resolve(c).then(o,function(A){return n(A),o()})}else p|=1}catch(A){n(A)}if(p===1)return t.hasError?Promise.reject(t.error):Promise.resolve();if(t.hasError)throw t.error}return o()}}(typeof SuppressedError=="function"?SuppressedError:function(e,t,n){var a=new Error(n);return a.name="SuppressedError",a.error=e,a.suppressed=t,a}),Sse=class extends sse{#e;#t;#i;constructor(t,n,a){super(),this.#e=t,this.#t=n,this.#i=a}get id(){return this.#i}targets(){return this.#t.targets().filter(t=>t.browserContext()===this)}async pages(){return(await Promise.all(this.targets().filter(n=>n.type()==="page"||n.type()==="other"&&this.#t._getIsPageTargetCallback()?.(n)).map(n=>n.page()))).filter(n=>!!n)}async overridePermissions(t,n){let a=n.map(p=>{let o=jme.get(p);if(!o)throw new Error("Unknown permission: "+p);return o});await this.#e.send("Browser.grantPermissions",{origin:t,browserContextId:this.#i||void 0,permissions:a})}async clearPermissionOverrides(){await this.#e.send("Browser.resetPermissions",{browserContextId:this.#i||void 0})}async newPage(){let t={stack:[],error:void 0,hasError:!1};try{let n=Ftr(t,await this.waitForScreenshotOperations(),!1);return await this.#t._createPageInContext(this.#i)}catch(n){t.error=n,t.hasError=!0}finally{Ktr(t)}}browser(){return this.#t}async close(){Uo(this.#i,"Default BrowserContext cannot be closed!"),await this.#t._disposeContext(this.#i)}};k();pS();Bd();ku();xd();W3();k();l_e();ku();W3();k();pS();c_e();MA();xd();dE();var fT=class extends MH{#e;#t;#i=new nX;#n;#r;#o;constructor(t,n,a,p){super(),this.#n=t,this.#t=n,this.#e=a,this.#r=p}_setTarget(t){this.#o=t}_target(){return Uo(this.#o,"Target must exist"),this.#o}connection(){return this.#n}parentSession(){return this.#r?this.#n?.session(this.#r)??void 0:this}send(t,n,a){return this.#n?this.#n._rawSend(this.#i,t,n,this.#e,a):Promise.reject(new hC(`Protocol error (${t}): Session closed. Most likely the ${this.#t} has been closed.`))}_onMessage(t){t.id?t.error?this.#i.reject(t.id,gLe(t),t.error.message):this.#i.resolve(t.id,t.result):(Uo(!t.id),this.emit(t.method,t.params))}async detach(){if(!this.#n)throw new Error(`Session already detached. Most likely the ${this.#t} has been closed.`);await this.#n.send("Target.detachFromTarget",{sessionId:this.#e})}_onClosed(){this.#i.clear(),this.#n=void 0,this.emit(D0.Disconnected,void 0)}id(){return this.#e}getPendingProtocolErrors(){return this.#i.getPendingProtocolErrors()}};k();gT();pS();GLe();qLe();MA();Bd();k();xd();var JLe=class{#e;#t;#i=!1;constructor(t,n){this.#e=t,this.#t=n.mode!=="selectSingle"}isMultiple(){return this.#t}async accept(t){Uo(!this.#i,"Cannot accept FileChooser which is already handled!"),this.#i=!0,await this.#e.uploadFile(...t)}async cancel(){Uo(!this.#i,"Cannot cancel FileChooser which is already handled!"),this.#i=!0,await this.#e.evaluate(t=>{t.dispatchEvent(new Event("cancel",{bubbles:!0}))})}};k();var gC;(function(e){e.Request=Symbol("NetworkManager.Request"),e.RequestServedFromCache=Symbol("NetworkManager.RequestServedFromCache"),e.Response=Symbol("NetworkManager.Response"),e.RequestFailed=Symbol("NetworkManager.RequestFailed"),e.RequestFinished=Symbol("NetworkManager.RequestFinished")})(gC||(gC={}));ku();xd();W3();Mg();dE();k();pS();c_e();Zae();MA();Bd();dE();var Otr=kH("puppeteer:protocol:SEND \u25BA"),Gtr=kH("puppeteer:protocol:RECV \u25C0"),YF=class extends _s{#e;#t;#i;#n;#r=new Map;#o=!1;#a=new Set;#c=new nX;constructor(t,n,a=0,p){super(),this.#e=t,this.#i=a,this.#n=p??18e4,this.#t=n,this.#t.onmessage=this.onMessage.bind(this),this.#t.onclose=this.#s.bind(this)}static fromSession(t){return t.connection()}get delay(){return this.#i}get timeout(){return this.#n}get _closed(){return this.#o}get _sessions(){return this.#r}session(t){return this.#r.get(t)||null}url(){return this.#e}send(t,n,a){return this._rawSend(this.#c,t,n,void 0,a)}_rawSend(t,n,a,p,o){return this.#o?Promise.reject(new Error("Protocol error: Connection closed.")):t.create(n,o?.timeout??this.#n,c=>{let A=JSON.stringify({method:n,params:a,id:c,sessionId:p});Otr(A),this.#t.send(A)})}async closeBrowser(){await this.send("Browser.close")}async onMessage(t){this.#i&&await new Promise(a=>setTimeout(a,this.#i)),Gtr(t);let n=JSON.parse(t);if(n.method==="Target.attachedToTarget"){let a=n.params.sessionId,p=new fT(this,n.params.targetInfo.type,a,n.sessionId);this.#r.set(a,p),this.emit(D0.SessionAttached,p);let o=this.#r.get(n.sessionId);o&&o.emit(D0.SessionAttached,p)}else if(n.method==="Target.detachedFromTarget"){let a=this.#r.get(n.params.sessionId);if(a){a._onClosed(),this.#r.delete(n.params.sessionId),this.emit(D0.SessionDetached,a);let p=this.#r.get(n.sessionId);p&&p.emit(D0.SessionDetached,a)}}if(n.sessionId){let a=this.#r.get(n.sessionId);a&&a._onMessage(n)}else n.id?n.error?this.#c.reject(n.id,gLe(n),n.error.message):this.#c.resolve(n.id,n.result):this.emit(n.method,n.params)}#s(){if(!this.#o){this.#o=!0,this.#t.onmessage=void 0,this.#t.onclose=void 0,this.#c.clear();for(let t of this.#r.values())t._onClosed();this.#r.clear(),this.emit(D0.Disconnected,void 0)}}dispose(){this.#s(),this.#t.close()}isAutoAttached(t){return!this.#a.has(t)}async _createSession(t,n=!0){n||this.#a.add(t.targetId);let{sessionId:a}=await this.send("Target.attachToTarget",{targetId:t.targetId,flatten:!0});this.#a.delete(t.targetId);let p=this.#r.get(a);if(!p)throw new Error("CDPSession creation failed.");return p}async createSession(t){return await this._createSession(t,!1)}getPendingProtocolErrors(){let t=[];t.push(...this.#c.getPendingProtocolErrors());for(let n of this.#r.values())t.push(...n.getPendingProtocolErrors());return t}};function p_e(e){return e instanceof hC}YLe();k();dLe();var jLe=class extends lse{#e;constructor(t,n,a,p=""){super(n,a,p),this.#e=t}async handle(t){await this.#e.send("Page.handleJavaScriptDialog",{accept:t.accept,promptText:t.text})}};ZLe();k();pS();Bd();xd();W3();var rX=class extends _s{#e;#t=new Map;#i=new Map;#n=new Map;#r;#o;#a=new WeakMap;#c=qu.create();#s=new Set;constructor(t,n,a){super(),this.#e=t,this.#r=a,this.#o=n,this.#e.on("Target.targetCreated",this.#l),this.#e.on("Target.targetDestroyed",this.#u),this.#e.on(D0.SessionDetached,this.#p),this.setupAttachmentListeners(this.#e)}setupAttachmentListeners(t){let n=a=>this.#h(t,a);Uo(!this.#a.has(t)),this.#a.set(t,n),t.on("Target.attachedToTarget",n)}#p=t=>{this.removeSessionListeners(t),this.#n.delete(t.id())};removeSessionListeners(t){this.#a.has(t)&&(t.off("Target.attachedToTarget",this.#a.get(t)),this.#a.delete(t))}getAvailableTargets(){return this.#i}getChildTargets(t){return new Set}dispose(){this.#e.off("Target.targetCreated",this.#l),this.#e.off("Target.targetDestroyed",this.#u)}async initialize(){await this.#e.send("Target.setDiscoverTargets",{discover:!0,filter:[{}]}),this.#s=new Set(this.#t.keys()),await this.#c.valueOrThrow()}#l=async t=>{if(this.#t.has(t.targetInfo.targetId))return;if(this.#t.set(t.targetInfo.targetId,t.targetInfo),t.targetInfo.type==="browser"&&t.targetInfo.attached){let a=this.#o(t.targetInfo,void 0);a._initialize(),this.#i.set(t.targetInfo.targetId,a),this.#d(a._targetId);return}let n=this.#o(t.targetInfo,void 0);if(this.#r&&!this.#r(n)){this.#d(t.targetInfo.targetId);return}n._initialize(),this.#i.set(t.targetInfo.targetId,n),this.emit("targetAvailable",n),this.#d(n._targetId)};#u=t=>{this.#t.delete(t.targetId),this.#d(t.targetId);let n=this.#i.get(t.targetId);n&&(this.emit("targetGone",n),this.#i.delete(t.targetId))};#h=async(t,n)=>{let a=n.targetInfo,p=this.#e.session(n.sessionId);if(!p)throw new Error(`Session ${n.sessionId} was not created.`);let o=this.#i.get(a.targetId);Uo(o,`Target ${a.targetId} is missing`),p._setTarget(o),this.setupAttachmentListeners(p),this.#n.set(p.id(),this.#i.get(a.targetId)),t.emit(D0.Ready,p)};#d(t){this.#s.delete(t),this.#s.size===0&&this.#c.resolve()}};k();pS();fse();Bd();ku();xd();W3();Mg();dE();k();var eBe=class{#e;#t;#i=new WeakMap;constructor(t,n,a){this.#e=n,this.#t=a,this.#i.set(t,n)}get id(){return this.#e}get source(){return this.#t}getIdForFrame(t){return this.#i.get(t)}setIdForFrame(t,n){this.#i.set(t,n)}};k();xd();W3();var dft=class{id;name;constructor(t,n){this.id=t,this.name=n}},gft=class{#e;#t;#i;#n=!1;#r=this.#a.bind(this);#o=new Set;devices=[];constructor(t,n,a){this.#e=t,this.#t=n,this.#i=a.id,this.#e.on("DeviceAccess.deviceRequestPrompted",this.#r),this.#e.on("Target.detachedFromTarget",()=>{this.#e=null}),this.#a(a)}#a(t){if(t.id===this.#i)for(let n of t.devices){if(this.devices.some(p=>p.id===n.id))continue;let a=new dft(n.id,n.name);this.devices.push(a);for(let p of this.#o)p.filter(a)&&p.promise.resolve(a)}}async waitForDevice(t,n={}){for(let c of this.devices)if(t(c))return c;let{timeout:a=this.#t.timeout()}=n,p=qu.create({message:`Waiting for \`DeviceRequestPromptDevice\` failed: ${a}ms exceeded`,timeout:a});n.signal&&n.signal.addEventListener("abort",()=>{p.reject(n.signal?.reason)},{once:!0});let o={filter:t,promise:p};this.#o.add(o);try{return await p.valueOrThrow()}finally{this.#o.delete(o)}}async select(t){return Uo(this.#e!==null,"Cannot select device through detached session!"),Uo(this.devices.includes(t),"Cannot select unknown device!"),Uo(!this.#n,"Cannot select DeviceRequestPrompt which is already handled!"),this.#e.off("DeviceAccess.deviceRequestPrompted",this.#r),this.#n=!0,await this.#e.send("DeviceAccess.selectPrompt",{id:this.#i,deviceId:t.id})}async cancel(){return Uo(this.#e!==null,"Cannot cancel prompt through detached session!"),Uo(!this.#n,"Cannot cancel DeviceRequestPrompt which is already handled!"),this.#e.off("DeviceAccess.deviceRequestPrompted",this.#r),this.#n=!0,await this.#e.send("DeviceAccess.cancelPrompt",{id:this.#i})}},tBe=class{#e;#t;#i=new Set;constructor(t,n){this.#e=t,this.#t=n,this.#e.on("DeviceAccess.deviceRequestPrompted",a=>{this.#n(a)}),this.#e.on("Target.detachedFromTarget",()=>{this.#e=null})}async waitForDevicePrompt(t={}){Uo(this.#e!==null,"Cannot wait for device prompt through detached session!");let n=this.#i.size===0,a;n&&(a=this.#e.send("DeviceAccess.enable"));let{timeout:p=this.#t.timeout()}=t,o=qu.create({message:`Waiting for \`DeviceRequestPrompt\` failed: ${p}ms exceeded`,timeout:p});t.signal&&t.signal.addEventListener("abort",()=>{o.reject(t.signal?.reason)},{once:!0}),this.#i.add(o);try{let[c]=await Promise.all([o.valueOrThrow(),a]);return c}finally{this.#i.delete(o)}}#n(t){if(!this.#i.size)return;Uo(this.#e!==null);let n=new gft(this.#e,this.#t,t);for(let a of this.#i)a.resolve(n);this.#i.clear()}};k();pS();Bd();Q$();t_e();ku();JV();Mg();W$();$me();Zme();k();TLe();ku();UF();xd();JV();dC();k();hse();ku();k();ku();xd();function Aft(e){let t,n;if(!e.exception)t="Error",n=e.text;else{if((e.exception.type!=="object"||e.exception.subtype!=="error")&&!e.exception.objectId)return BH(e.exception);{let A=uwi(e);t=A.name,n=A.message}}let a=n.split(`
|
1425
1425
|
`).length,p=new Error(n);p.name=t;let o=p.stack.split(`
|
1426
1426
|
`),c=o.splice(0,a);if(o.shift(),e.stackTrace&&o.length<Error.stackTraceLimit)for(let A of e.stackTrace.callFrames.reverse()){if(w6.isPuppeteerURL(A.url)&&A.url!==w6.INTERNAL_URL){let m=w6.parse(A.url);o.unshift(` at ${A.functionName||m.functionName} (${m.functionName} at ${m.siteString}, <anonymous>:${A.lineNumber}:${A.columnNumber})`)}else o.push(` at ${A.functionName||"<anonymous>"} (${A.url}:${A.lineNumber}:${A.columnNumber})`);if(o.length>=Error.stackTraceLimit)break}return p.stack=[...c,...o].join(`
|
1427
1427
|
`),p}var uwi=e=>{let t="",n,a=e.exception?.description?.split(`
|
package/docs/index.md
CHANGED
@@ -66,14 +66,13 @@ By using Sentinel, you agree to our [DISCLAIMER]({{ site.url }}{{ site.baseurl }
|
|
66
66
|
## 📄 Detailed Documentation
|
67
67
|
|
68
68
|
- [Introduction]({{ site.url }}{{ site.baseurl }})
|
69
|
+
- [Spider Scanner]({{ site.url }}{{ site.baseurl }}/spider/)
|
69
70
|
- [XSS Scanner]({{ site.url }}{{ site.baseurl }}/xss/)
|
70
|
-
- [
|
71
|
-
- [Details]({{ site.url }}{{ site.baseurl }}/xss/details)
|
71
|
+
- [Vulnerability Details]({{ site.url }}{{ site.baseurl }}/xss/details)
|
72
72
|
- [HTTP Headers Scanner]({{ site.url }}{{ site.baseurl }}/headers/)
|
73
|
-
- [
|
74
|
-
|
75
|
-
- [
|
76
|
-
- [Usage]({{ site.url }}{{ site.baseurl }}/spider/)
|
73
|
+
- [Vulnerability Details]({{ site.url }}{{ site.baseurl }}/headers/details)
|
74
|
+
- [SQL Injection Scanner]({{ site.url }}{{ site.baseurl }}/sql-injection/)
|
75
|
+
- [Vulnerability Details]({{ site.url }}{{ site.baseurl }}/sql-injection/details)
|
77
76
|
- [Scoring]({{ site.url }}{{ site.baseurl }}/scoring/)
|
78
77
|
- [Disclaimer]({{ site.url }}{{ site.baseurl }}/disclaimer/)
|
79
78
|
|
@@ -0,0 +1,109 @@
|
|
1
|
+
---
|
2
|
+
layout: default
|
3
|
+
title: Sentinel by Rebackk | SQL Injection Details
|
4
|
+
---
|
5
|
+
### **Understanding SQL Injection (SQLi): Protecting Your Web Applications**
|
6
|
+
|
7
|
+
#### **Introduction**
|
8
|
+
SQL Injection (SQLi) is one of the most dangerous and prevalent web vulnerabilities, regularly appearing on the OWASP Top Ten list. Attackers exploit SQLi to manipulate backend databases through malicious SQL queries. By injecting malicious code into a website's input fields or URL parameters, attackers can view, modify, or delete data, potentially leading to significant security breaches. In this guide, we’ll explore what SQL Injection is, the different types of SQLi attacks, real-world examples, and how you can protect your applications using Rebackk's Sentinel tool.
|
9
|
+
|
10
|
+
---
|
11
|
+
|
12
|
+
### **What is SQL Injection (SQLi)?**
|
13
|
+
SQL Injection is a vulnerability that allows attackers to interfere with the queries your application sends to its database. By injecting malicious SQL code into input fields (like login forms, search bars, or URL parameters), attackers can manipulate or extract sensitive data, bypass authentication, or even execute administrative database commands.
|
14
|
+
|
15
|
+
#### **Types of SQL Injection Attacks**
|
16
|
+
1. **In-band SQLi (Classic SQLi)**:
|
17
|
+
This is the most common form of SQLi. The attacker uses the same communication channel to both launch the attack and gather results, such as through error messages or retrieving data from the database.
|
18
|
+
|
19
|
+
2. **Blind SQLi**:
|
20
|
+
In this type of attack, the attacker does not get the results directly. Instead, they infer the presence of vulnerabilities based on the application's behavior (e.g., timing or changes in responses). Blind SQLi is more difficult to detect but still dangerous.
|
21
|
+
|
22
|
+
- **Boolean-based Blind SQLi**: The attacker sends a query that forces the application to return different results depending on the condition (true or false).
|
23
|
+
- **Time-based Blind SQLi**: The attacker induces a delay in the database response, which helps infer whether the query is correct.
|
24
|
+
|
25
|
+
3. **Out-of-Band SQLi**:
|
26
|
+
This type of SQLi is rare but sophisticated. The attacker relies on the server’s ability to make DNS or HTTP requests to a remote server. Results are retrieved through these external channels, such as by creating DNS requests or HTTP responses.
|
27
|
+
|
28
|
+
---
|
29
|
+
|
30
|
+
### **How SQL Injection Works: A Real-World Example**
|
31
|
+
|
32
|
+
Consider a user visiting a login page with a vulnerable form. If the application doesn’t properly sanitize user input, an attacker could enter the following SQL code in the username or password field:
|
33
|
+
|
34
|
+
```sql
|
35
|
+
' OR 1=1 --
|
36
|
+
```
|
37
|
+
|
38
|
+
This could turn the SQL query into:
|
39
|
+
|
40
|
+
```sql
|
41
|
+
SELECT * FROM users WHERE username = '' OR 1=1 --' AND password = 'userpassword';
|
42
|
+
```
|
43
|
+
|
44
|
+
Since `1=1` is always true, the query would return all records in the database, potentially allowing the attacker to bypass authentication and gain unauthorized access to the system.
|
45
|
+
|
46
|
+
---
|
47
|
+
|
48
|
+
### **How to Detect SQL Injection Vulnerabilities**
|
49
|
+
Using **Sentinel**, Rebackk’s AI-powered vulnerability scanner, you can easily detect SQL Injection vulnerabilities in your web applications. Here’s how to use it:
|
50
|
+
|
51
|
+
1. **Run a Scan**:
|
52
|
+
```bash
|
53
|
+
npx sentinel-scanner sqli -s <path_to_spider_results>
|
54
|
+
```
|
55
|
+
2. **Analyze the Results**:
|
56
|
+
- Sentinel generates a detailed report, highlighting any SQLi vulnerabilities detected in your web application.
|
57
|
+
- It offers actionable recommendations to fix the vulnerabilities.
|
58
|
+
|
59
|
+
---
|
60
|
+
|
61
|
+
### **Best Practices for Preventing SQL Injection Attacks**
|
62
|
+
|
63
|
+
1. **Use Prepared Statements (Parameterized Queries)**:
|
64
|
+
- Prepared statements ensure that user inputs are treated as data and not executable code. This is the most effective way to prevent SQLi.
|
65
|
+
|
66
|
+
Example (in PHP with PDO):
|
67
|
+
```php
|
68
|
+
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = :username');
|
69
|
+
$stmt->execute(['username' => $userInput]);
|
70
|
+
```
|
71
|
+
|
72
|
+
2. **Sanitize and Escape User Inputs**:
|
73
|
+
- Use input validation and sanitization to ensure that data entered by users is safe.
|
74
|
+
- Use functions like `mysqli_real_escape_string` (in PHP) to escape dangerous characters.
|
75
|
+
|
76
|
+
3. **Use ORM (Object-Relational Mapping) Frameworks**:
|
77
|
+
- ORM libraries automatically handle query generation, reducing the risk of SQLi by using parameterized queries behind the scenes.
|
78
|
+
|
79
|
+
4. **Limit Database Permissions**:
|
80
|
+
- Ensure that the database account used by the web application has the least amount of privilege necessary to function. For example, avoid using an admin account for web application queries.
|
81
|
+
|
82
|
+
5. **Error Handling**:
|
83
|
+
- Avoid exposing detailed database error messages to users. Use generic error messages to prevent attackers from gaining insight into your database structure.
|
84
|
+
|
85
|
+
6. **Implement Web Application Firewalls (WAF)**:
|
86
|
+
- A WAF can help detect and block malicious SQLi attempts before they reach your application.
|
87
|
+
|
88
|
+
---
|
89
|
+
|
90
|
+
### **Using Rebackk’s Sentinel for Continuous Security**
|
91
|
+
With Sentinel’s automated scanning, you can set up continuous monitoring to detect SQL Injection vulnerabilities before attackers exploit them.
|
92
|
+
|
93
|
+
**Key Features**:
|
94
|
+
- **AI-Powered Analysis**: Quickly scans your web apps for SQLi vulnerabilities.
|
95
|
+
- **Detailed Reports**: Provides step-by-step guides on how to fix detected issues.
|
96
|
+
- **OWASP Top Ten Coverage**: Ensures protection against common vulnerabilities like SQLi, XSS, and more.
|
97
|
+
|
98
|
+
---
|
99
|
+
|
100
|
+
### **Conclusion**
|
101
|
+
SQL Injection remains one of the most critical vulnerabilities in web applications, but by applying best practices and using tools like Rebackk’s Sentinel, you can protect your application from these dangerous attacks. Regularly scan your applications, sanitize inputs, and implement security best practices to stay ahead of attackers.
|
102
|
+
|
103
|
+
Start securing your applications today with **Sentinel**. Visit [Rebackk](https://rebackk.xyz) to learn more and try it for free.
|
104
|
+
|
105
|
+
---
|
106
|
+
|
107
|
+
#### **Additional Resources**
|
108
|
+
- [OWASP SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html)
|
109
|
+
- [Sentinel Web App Scanner Documentation](https://rebackkhq.github.io/webapp-scanner/)
|
@@ -0,0 +1,73 @@
|
|
1
|
+
---
|
2
|
+
layout: default
|
3
|
+
title: Sentinel by Rebackk | SQLi Scanner
|
4
|
+
---
|
5
|
+
## Sentinel by Rebackk | SQLi Scanner Intro
|
6
|
+
|
7
|
+
# 🛡️ SQLi Scanner
|
8
|
+
|
9
|
+
A powerful SQL Injection (SQLi) vulnerability scanner that uses the output from a Spider crawler to identify SQL Injection vulnerabilities on each page of a website. It supports concurrency, retries, and customizable timeouts, ensuring efficient and thorough scanning.
|
10
|
+
|
11
|
+
## Features
|
12
|
+
|
13
|
+
- **Leverages Spider Results**: Uses URLs collected by the Spider tool to perform targeted SQL Injection scanning.
|
14
|
+
- **Customizable Concurrency**: Supports multiple requests in parallel to speed up the scanning process.
|
15
|
+
- **Retries on Failure**: Automatically retries failed requests to ensure reliable results.
|
16
|
+
- **Timeout Handling**: Configurable timeout for each request to manage slow or unresponsive pages.
|
17
|
+
- **Output in JSON Format**: Saves the scan results in a detailed and easily accessible JSON file.
|
18
|
+
- **Command Line Interface (CLI)**: Provides a simple yet powerful CLI for quick and flexible scanning.
|
19
|
+
|
20
|
+
## Installation and Usage
|
21
|
+
|
22
|
+
### Using NPM Exec
|
23
|
+
|
24
|
+
- Install the `sentinel-scanner` globally:
|
25
|
+
```bash
|
26
|
+
npm install -g sentinel-scanner
|
27
|
+
```
|
28
|
+
|
29
|
+
- Run the **SQLi Scanner** using the Spider results:
|
30
|
+
```bash
|
31
|
+
npx sentinel-scanner sqli -s <path_to_spider_results>
|
32
|
+
```
|
33
|
+
|
34
|
+
## Using PreBuilt Releases
|
35
|
+
|
36
|
+
- Download the [Latest Release](https://github.com/RebackkHQ/webapp-scanner/releases/latest).
|
37
|
+
- Extract the files.
|
38
|
+
- Run the SQLi Scanner from the command line:
|
39
|
+
```bash
|
40
|
+
npx . sqli -s <path_to_spider_results>
|
41
|
+
```
|
42
|
+
|
43
|
+
## Parameters
|
44
|
+
|
45
|
+
### Options
|
46
|
+
|
47
|
+
| Option | Alias | Type | Default | Description |
|
48
|
+
|--------------------|-------|----------|----------------------------------------------|-------------------------------------------------------------------|
|
49
|
+
| `--spiderResults` | `-s` | `string` | - | Path to the spider results file (**required**). |
|
50
|
+
| `--output` | `-o` | `string` | `sentinel_output/sqliResult_<timestamp>.json` | Path to save the output JSON file. |
|
51
|
+
| `--concurrency` | `-c` | `number` | 10 | Number of concurrent requests (range: 1-20). |
|
52
|
+
| `--timeout` | `-t` | `number` | 5000 (ms) | Timeout for each request in milliseconds (range: 0-25,000). |
|
53
|
+
| `--retries` | `-r` | `number` | 3 | Number of retries for each request (range: 0-10). |
|
54
|
+
|
55
|
+
## Example Commands
|
56
|
+
|
57
|
+
### Basic Scan
|
58
|
+
To scan for SQL Injection vulnerabilities using Spider results:
|
59
|
+
```bash
|
60
|
+
npx sentinel-scanner sqli -s spiderResults.json
|
61
|
+
```
|
62
|
+
|
63
|
+
### Advanced Scan with Custom Output and Concurrency
|
64
|
+
To scan with custom concurrency, timeout, and output path:
|
65
|
+
```bash
|
66
|
+
npx sentinel-scanner sqli -s spiderResults.json -c 15 -t 8000 -o ./output/sqliScanResults.json
|
67
|
+
```
|
68
|
+
|
69
|
+
### Default Output Path
|
70
|
+
If the `--output` option is not specified, the results will be saved to:
|
71
|
+
```
|
72
|
+
sentinel_output/sqliResult_<timestamp>.json
|
73
|
+
```
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "sentinel-scanner",
|
3
3
|
"description": "[WIP] An open-source web app vulnerability scanner developed by Rebackk.",
|
4
|
-
"version": "2.
|
4
|
+
"version": "2.3.0",
|
5
5
|
"exports": "./build/index.js",
|
6
6
|
"types": "./build/index.d.ts",
|
7
7
|
"bin": "./build/bin.js",
|
@@ -16,6 +16,26 @@
|
|
16
16
|
"node": "^22.11.0",
|
17
17
|
"npm": "^10.5.0"
|
18
18
|
},
|
19
|
+
"keywords": [
|
20
|
+
"nodejs",
|
21
|
+
"npm-package",
|
22
|
+
"owasp",
|
23
|
+
"sentinel",
|
24
|
+
"cybersecurity",
|
25
|
+
"penetration-testing",
|
26
|
+
"web-security",
|
27
|
+
"vulnerability-detection",
|
28
|
+
"vulnerability-scanner",
|
29
|
+
"api-security",
|
30
|
+
"threat-detection",
|
31
|
+
"security-tool",
|
32
|
+
"webapp-scanner",
|
33
|
+
"ai-powered",
|
34
|
+
"automated-scanning",
|
35
|
+
"spider-scanner",
|
36
|
+
"scanner",
|
37
|
+
"typescript"
|
38
|
+
],
|
19
39
|
"publishConfig": {
|
20
40
|
"access": "public"
|
21
41
|
},
|
package/src/bin.ts
CHANGED
@@ -4,6 +4,7 @@ import yargs from "yargs";
|
|
4
4
|
import { hideBin } from "yargs/helpers";
|
5
5
|
import { headerCommand } from "./commands/header.js";
|
6
6
|
import { spiderCommand } from "./commands/spider.js";
|
7
|
+
import { sqliCommand } from "./commands/sqli.js";
|
7
8
|
import { xssCommand } from "./commands/xss.js";
|
8
9
|
|
9
10
|
const commandHandler = yargs(hideBin(process.argv));
|
@@ -20,5 +21,7 @@ commandHandler.showHelpOnFail(true);
|
|
20
21
|
commandHandler.command(spiderCommand);
|
21
22
|
commandHandler.command(xssCommand);
|
22
23
|
commandHandler.command(headerCommand);
|
24
|
+
commandHandler.command(sqliCommand);
|
23
25
|
|
26
|
+
commandHandler.version();
|
24
27
|
commandHandler.parse();
|
@@ -0,0 +1,150 @@
|
|
1
|
+
import fs from "node:fs/promises";
|
2
|
+
import path from "node:path";
|
3
|
+
import type { ArgumentsCamelCase, CommandModule } from "yargs";
|
4
|
+
import SqliScanner from "../modules/sqli/index.js";
|
5
|
+
import { createLogger } from "../utils/index.js";
|
6
|
+
|
7
|
+
export type SqliScannerCLIoptions = {
|
8
|
+
spiderResults: string;
|
9
|
+
retries?: number;
|
10
|
+
timeout?: number;
|
11
|
+
concurrency?: number;
|
12
|
+
output?: string;
|
13
|
+
};
|
14
|
+
|
15
|
+
const cliLogger = createLogger("CLI");
|
16
|
+
|
17
|
+
export const sqliCommand: CommandModule = {
|
18
|
+
command: "sqli",
|
19
|
+
describe:
|
20
|
+
"Check a website for SQL Injection vulnerabilities by scanning each page",
|
21
|
+
builder: (yargs) => {
|
22
|
+
return yargs
|
23
|
+
.option("spiderResults", {
|
24
|
+
alias: "s",
|
25
|
+
type: "string",
|
26
|
+
description:
|
27
|
+
"The spider results file to use for scanning. It will use the URLs from the spider results to scan for SQL Injection vulnerabilities",
|
28
|
+
demandOption: true,
|
29
|
+
coerce: (url) => {
|
30
|
+
if (!path.isAbsolute(url)) {
|
31
|
+
return path.resolve(url);
|
32
|
+
}
|
33
|
+
return url;
|
34
|
+
},
|
35
|
+
})
|
36
|
+
.option("output", {
|
37
|
+
alias: "o",
|
38
|
+
type: "string",
|
39
|
+
description:
|
40
|
+
"The output file to write the results to. Must be a JSON file",
|
41
|
+
default: () => getDefaultFilePath(),
|
42
|
+
coerce: (output) => {
|
43
|
+
const resolvedPath = path.resolve(output);
|
44
|
+
const { ext } = path.parse(resolvedPath);
|
45
|
+
|
46
|
+
if (ext !== ".json") {
|
47
|
+
throw new Error("Output file must be a JSON file");
|
48
|
+
}
|
49
|
+
return resolvedPath;
|
50
|
+
},
|
51
|
+
})
|
52
|
+
.option("concurrency", {
|
53
|
+
alias: "c",
|
54
|
+
type: "number",
|
55
|
+
description: "The number of concurrent requests to make",
|
56
|
+
default: 10,
|
57
|
+
coerce: (concurrency) => {
|
58
|
+
if (concurrency < 1 || concurrency > 20) {
|
59
|
+
throw new Error("Concurrency must be between 1 and 20");
|
60
|
+
}
|
61
|
+
return concurrency;
|
62
|
+
},
|
63
|
+
})
|
64
|
+
.option("timeout", {
|
65
|
+
alias: "t",
|
66
|
+
type: "number",
|
67
|
+
description: "The timeout for each request in milliseconds",
|
68
|
+
default: 5000,
|
69
|
+
coerce: (timeout) => {
|
70
|
+
if (timeout < 0 || timeout > 25000) {
|
71
|
+
throw new Error("Timeout must be between 0 and 25,000 ms");
|
72
|
+
}
|
73
|
+
return timeout;
|
74
|
+
},
|
75
|
+
})
|
76
|
+
.option("retries", {
|
77
|
+
alias: "r",
|
78
|
+
type: "number",
|
79
|
+
description: "The number of retries for each request",
|
80
|
+
default: 3,
|
81
|
+
coerce: (retries) => {
|
82
|
+
if (retries < 0 || retries > 10) {
|
83
|
+
throw new Error("Retries must be between 0 and 10");
|
84
|
+
}
|
85
|
+
return retries;
|
86
|
+
},
|
87
|
+
});
|
88
|
+
},
|
89
|
+
handler: async (args) => {
|
90
|
+
try {
|
91
|
+
const argData = args as ArgumentsCamelCase<SqliScannerCLIoptions>;
|
92
|
+
const spiderResultsPath = path.resolve(argData.spiderResults);
|
93
|
+
|
94
|
+
// Check if the spider results file exists
|
95
|
+
if (!(await fileExists(spiderResultsPath))) {
|
96
|
+
throw new Error(
|
97
|
+
`Spider results file not found at ${spiderResultsPath}`,
|
98
|
+
);
|
99
|
+
}
|
100
|
+
|
101
|
+
const spiderResults = JSON.parse(
|
102
|
+
await fs.readFile(spiderResultsPath, "utf-8"),
|
103
|
+
);
|
104
|
+
|
105
|
+
cliLogger.info("Starting XSS scan on website");
|
106
|
+
|
107
|
+
const scanner = new SqliScanner({
|
108
|
+
spiderResults,
|
109
|
+
concurrency: argData.concurrency,
|
110
|
+
timeout: argData.timeout,
|
111
|
+
retries: argData.retries,
|
112
|
+
});
|
113
|
+
|
114
|
+
const results = await scanner.scan();
|
115
|
+
|
116
|
+
const outputPath = argData.output || getDefaultFilePath();
|
117
|
+
await fs.writeFile(outputPath, JSON.stringify(results, null, 2));
|
118
|
+
cliLogger.info(`Results successfully written to ${outputPath}`);
|
119
|
+
} catch (error) {
|
120
|
+
if (error instanceof Error) {
|
121
|
+
cliLogger.error(`Error: ${error.message}`);
|
122
|
+
}
|
123
|
+
cliLogger.error("Failed to run SQLI command");
|
124
|
+
process.exit(1);
|
125
|
+
}
|
126
|
+
},
|
127
|
+
};
|
128
|
+
|
129
|
+
// Utility function to check if a file exists
|
130
|
+
const fileExists = async (filePath: string) => {
|
131
|
+
try {
|
132
|
+
await fs.access(filePath);
|
133
|
+
return true;
|
134
|
+
} catch {
|
135
|
+
return false;
|
136
|
+
}
|
137
|
+
};
|
138
|
+
|
139
|
+
// Utility function to get the default file path
|
140
|
+
const getDefaultFilePath = () => {
|
141
|
+
const resolvedDir = path.resolve("sentinel_output");
|
142
|
+
|
143
|
+
// Ensure the directory exists or create it
|
144
|
+
fs.mkdir(resolvedDir, { recursive: true }).catch((err) => {
|
145
|
+
cliLogger.error(`Failed to create directory: ${err.message}`);
|
146
|
+
process.exit(1);
|
147
|
+
});
|
148
|
+
|
149
|
+
return path.resolve(resolvedDir, `sqliResult_${Date.now()}.json`);
|
150
|
+
};
|