Is litellm safe?
- Python shell/command execution
- Python dynamic code execution
- Node.js shell/command execution
litellm is an AI python_package analyzed by SkillTotal's deterministic static scanner. The scan found no malicious indicators, though 11 risky constructs are reported for review. It can: dynamic code execution, filesystem read, filesystem write, mcp tools detected, network egress and shell execution — capabilities are what the code can do, not a verdict on intent. Risk score 30/100 (medium).
litellm 1.91.0
Automated static-analysis result. It can contain false positives and false negatives, and is not a claim about the intent of litellm's authors. Report a false positive.
Findings (11)
The code turns strings into live code at runtime (eval / new Function / exec).
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,314044,(e,t,a)=>{t.exports=function(){for(var e={},t=0;t<arguments.length;t++){var a=arguments[t];for(var r in a)n.call(a,r)&&(e …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,166068,e=>{"use strict";let t=(e,t,a,i,o,n,s)=>({id:e,framework:t,category:a,categoryIcon:i,categoryDescription:o,prompt:n,expec …!function webpackUniversalModuleDefinition(s,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports.SwaggerUIBundle=o():s.SwaggerUIBundle=o …Why it matters: If those strings aren't fixed and trusted, they become a way to run arbitrary code.
Fix: Avoid evaluating dynamically constructed code; if unavoidable, ensure the input is a trusted constant and never derived from external data.
The code turns strings into live code at runtime (eval / new Function / exec).
exec(compiled, exec_globals) # noqa: S102
exec(compiled, exec_globals) # noqa: S102
Why it matters: If those strings aren't fixed and trusted, they become a way to run arbitrary code.
Fix: Avoid evaluating dynamically constructed code; if unavoidable, ensure the input is a trusted constant and never derived from external data.
A command uses a known defense-evasion idiom: PowerShell execution-policy bypass / encoded command / hidden window, macOS code-signing bypass, or launching a payload from a world-writable temp directory. These are hallmarks of droppers and rarely appear in legitimate code. (2 occurrence(s) shown as evidence).
!function webpackUniversalModuleDefinition(s,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports.SwaggerUIBundle=o():s.SwaggerUIBundle=o …Fix: Verify why the component bypasses execution policy / code signing or runs from a temp directory; these patterns are characteristic of malware staging.
The component can run operating-system commands or spawn processes.
`]:{animationName:i.slideDownOut},"&-hidden":{display:"none"},[o]:Object.assign(Object.assign({},l(e)),{cursor:"pointer",transition:`background ${e.motionDurationSlow} ease`,borderRadius:e.borderRadiusSM,"&-group":{color:e.colorTextDescript …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,115504,e=>{"use strict";var r=e.i(207670);let o=e=>"boolean"==typeof e?`${e}`:0===e?"0":e,t=e=>{let t=function(){for(var o,t,l=a …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,649222,(e,a,t)=>{e.e,e.r(166540).defineLocale("af",{months:"Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Ok …!function(){var t="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function e(t){var e={exports:{}};return t(e,e.exports),e.exports}var r,n,o=func …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,423755,(e,t,n)=>{"use strict";Object.defineProperty(n,"__esModule",{value:!0});let r=(0,e.r(543369).getDeploymentId)();globalThi …${t}`))}function X(){let e=new AbortController;return e.abort(Object.defineProperty(new g.BailoutToCSRError("Render in Browser"),"__NEXT_ERROR_CODE",{value:"E721",enumerable:!1,configurable:!0})),e.signal}function H(e){switch(e.type){case"p …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,314044,(e,t,a)=>{t.exports=function(){for(var e={},t=0;t<arguments.length;t++){var a=arguments[t];for(var r in a)n.call(a,r)&&(e …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,166068,e=>{"use strict";let t=(e,t,a,i,o,n,s)=>({id:e,framework:t,category:a,categoryIcon:i,categoryDescription:o,prompt:n,expec …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,467034,(e,t,r)=>{var s={675:function(e,t){"use strict";t.byteLength=function(e){var t=l(e),r=t[0],s=t[1];return(r+s)*3/4-s},t.to …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,35983,992704,877891,401141,952744,605083,101852,919751,178677,635307,495470,333771,e=>{"use strict";let t,n,r,o,l;var i=e.i(2905 …`]:{opacity:1}},[`${t}-icon ${n}`]:{color:e.colorIcon,fontSize:r},[`${l}-progress`]:{position:"absolute",bottom:e.calc(e.uploadProgressOffset).mul(-1).equal(),width:"100%",paddingInlineStart:i(r).add(e.paddingXS).equal(),fontSize:r,lineHeig …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,224283,(t,e,r)=>{var n=t.r(374009),o=t.r(950724);e.exports=function(t,e,r){var i=!0,a=!0;if("function"!=typeof t)throw TypeError …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,126568,(e,t,n)=>{"use strict";var r=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//g,i=/\n/g,l=/^\s*/,o=/^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s* …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,66899,e=>{"use strict";var t=e.i(843476),s=e.i(271645),r=e.i(994388),l=e.i(212931),a=e.i(199133),n=e.i(602869),o=e.i(269200),i=e …main();`}})())},[m,x,h,e,n,o]),(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(r.Button,{variant:"secondary",icon:q.CodeOutlined,onClick:()=>{p(!0)},children:"Get Code"}),(0,t.jsxs)(l.Modal,{title:"Generated Code",open:m,onCancel:()=>{p(!1)},foo …}`,eo=({visible:e,initialJson:r,onSave:a,onClose:n})=>{let[o,i]=(0,s.useState)(r||en),[c,d]=(0,s.useState)(null),m=()=>{d(null),n()};return(0,t.jsx)(l.Modal,{title:(0,t.jsx)("div",{className:"flex items-center justify-between",children:(0,t …`}),(0,t.jsx)(ew,{value:e,onChange:e=>r(e.target.value),placeholder:l,rows:a,className:"font-sans"}),p.length>0&&(0,t.jsxs)("div",{className:"mt-2 flex flex-wrap gap-2 items-center",children:[(0,t.jsx)("span",{className:"text-xs text-gray-5 …Read more: https://nextjs.org/docs/messages/next-image-missing-loader`),"__NEXT_ERROR_CODE",{value:"E252",enumerable:!1,configurable:!0})}else{let e=z;z=t=>{let{config:s,...r}=t;return e(r)}}if(k){"fill"===k&&(x=!0);let e={intrinsic:{maxWid …...and ${r.length-5} more errors`:""));if(0===a.length)return void en("No valid prompts found in CSV.");k(e=>[...e,...a]),v(e=>{let t=new Set(e);return a.forEach(e=>t.add(e.framework)),t}),w(e=>{let t=new Set(e);return a.forEach(e=>t.add(e. …Please migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`),r1.includes(e.model)&&e.thinking&&"enabled"===e.thinking.type&&console.warn(`Using Claude with ${e.model} and 'th …}'`;return(0,ey.jsxs)("div",{className:"mx-auto max-w-3xl space-y-6",children:[(0,ey.jsxs)("div",{children:[(0,ey.jsx)("h3",{className:"text-sm font-semibold text-gray-900 mb-1",children:"Proxy base URL"}),(0,ey.jsx)("p",{className:"text-sm …!function webpackUniversalModuleDefinition(s,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports.SwaggerUIBundle=o():s.SwaggerUIBundle=o …Why it matters: Powerful and often legitimate — confirm the commands aren't built from untrusted input.
Fix: Confirm the command and its arguments are fully controlled and not derived from untrusted input; prefer execFile with an argument array.
The component can run operating-system commands or spawn processes.
subprocess.check_call([sys.executable, "-m", "pip", "install", "supabase"])
subprocess.check_call([sys.executable, "-m", "pip", "install", "sentry_sdk"])
subprocess.check_call([sys.executable, "-m", "pip", "install", "slack_bolt"])
result = subprocess.run(
[
"prisma",
"migrate",
"diff",
"--from-url",
db_url,
"--to-schema-datamodel",
"./schema.pri …subprocess.run(
[
"prisma",
"db",
"push",
"--accept-data-loss",
"--skip-gene …result = subprocess.run(["prisma", "generate"], capture_output=True, text=True)
subprocess.Popen(command, stdout=devnull, stderr=devnull)
subprocess.run(["prisma"], capture_output=True)
subprocess.Popen(command, stdout=devnull, stderr=devnull)
Why it matters: Powerful and often legitimate — confirm the commands aren't built from untrusted input.
Fix: Confirm the command and its arguments are fully controlled and not derived from untrusted input; avoid shell=True.
A server is bound to all network interfaces (0.0.0.0), not just your own machine.
"0.0.0.0",
- if litellm.force_ipv4 is True, it will return AsyncHTTPTransport with local_address="0.0.0.0"
"local_addr": ("0.0.0.0", 0) if litellm.force_ipv4 else None,- If force_ipv4 is True, it will create an AsyncHTTPTransport with local_address set to "0.0.0.0"
return AsyncHTTPTransport(local_address="0.0.0.0")
return HTTPTransport(local_address="0.0.0.0")
@click.option("--host", default="0.0.0.0", help="Host for the server to listen on.", envvar="HOST")Why it matters: Without authentication, other hosts on the network can reach it.
Fix: Bind to 127.0.0.1 for local-only use, or require authentication and restrict access if remote exposure is intended.
The component reads files from disk.
files("litellm").joinpath("anthropic_beta_headers_config.json").read_text(encoding="utf-8")with open("user_cost.json", "r") as json_file:with open(config_path) as f:
content = file_path.read_text(encoding="utf-8")
content = file_path.read_text(encoding="utf-8")
with open(json_path, "r") as f:
with open(file_path, "rb") as f:
with open(str(content), "rb") as f:
with open(str(file_content_obj), "rb") as f:
return open(file_path, "rb")
with open(str(file), "rb") as f:
with open(token_file, "r") as f:
content = json.loads(files("litellm").joinpath("blog_posts.json").read_text(encoding="utf-8"))files("litellm").joinpath("model_prices_and_context_window_backup.json").read_text(encoding="utf-8")with open(file_content, "rb") as f:
with open(web_identity_token_file, "r") as f:
with open(str(file_content), "rb") as f:
with open(str(file_content), "rb") as f:
with open(image, "rb") as f:
with open(self.auth_file, "r") as f:
with open(config_path) as f:
with open(self.access_token_file, "r") as f:
with open(self.api_key_file, "r") as f:
with open(self.api_key_file, "r") as f:
with open(file_path, "r") as file:
Why it matters: Usually legitimate, but worth confirming it can't be steered into reading sensitive files.
Fix: Confirm which files are read and that paths cannot be influenced by untrusted input to reach sensitive locations.
The component writes or deletes files on disk.
with open("user_cost.json", "w") as json_file:with open(self.auth_file, "w") as f:
with open(self.access_token_file, "w") as f:
with open(self.api_key_file, "w") as f:
with open(local_path, "wb") as f:
os.unlink(local_requirements_path)
os.unlink(tmp_path)
os.unlink(tmp_path)
with open(cert_path, "w") as f:
with open(key_path, "w") as f:
os.unlink(tmp_file)
SNAPSHOT_FILE.write_text(json.dumps(fragments, indent=2, sort_keys=True) + "\n")
with open(token_file, "w") as f:
os.remove(token_file)
with open(filename, "w") as f:
with open(local_file_path, "w") as f:
with open(local_file_path, "w") as f:
os.remove(filepath)
temp_file_path.write_bytes(file_content)
with open(os.devnull, "w") as devnull:
shutil.copytree(
source_path,
target_path,
dirs_exist_ok=True,
)with open(file_path, "w", encoding="utf-8") as f:
with open(os.devnull, "w") as devnull:
with open(f"{user_config_file_path}", "w") as config_file:Why it matters: Usually legitimate, but worth confirming the paths can't be controlled by untrusted input.
Fix: Confirm which files are written/deleted and that paths cannot be influenced by untrusted input.
The component makes outbound network requests.
margin-bottom ${n} ${c}`},[`&${t}-motion-leave-active`]:{maxHeight:0,marginBottom:"0 !important",paddingTop:0,paddingBottom:0,opacity:0}}),[`${t}-with-description`]:{alignItems:"flex-start",padding:g,[`${t}-icon`]:{marginInlineEnd:a,fontSiz …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,618566,(e,t,r)=>{t.exports=e.r(976562)},612256,869230,469637,266027,243652,e=>{"use strict";let t;var r=e.i(602869),n=e.i(175555 …Allowed values: ${r.enum.join(", ")}`:E)}),children:u},e)})}):null};class g extends Error{status;body;constructor(e,t,r){super(e),this.name="ApiError",this.status=t,this.body=r}}let h=e=>{let t=e?.detail,r=Array.isArray(t)?t.map(e=>e?.msg|| …${t}`}],339019)},596239,e=>{"use strict";e.i(247167);var t=e.i(931067),i=e.i(271645);let a={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M574 665.4a8.03 8.03 0 00-11.3 0L446.5 781.6c-53.8 …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,599724,936325,e=>{"use strict";var t=e.i(95779),r=e.i(444755),o=e.i(673706),i=e.i(271645);let n=i.default.forwardRef((e,n)=>{let …`]:Object.assign({},{background:e.skeletonLoadingBackground,backgroundSize:"400% 100%",animationName:u,animationDuration:e.skeletonLoadingMotionDuration,animationTimingFunction:"ease",animationIterationCount:"infinite"})}}})((0,c.mergeToken …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,21548,e=>{"use strict";var t=e.i(616303);e.s(["Empty",()=>t.default])},482725,e=>{"use strict";var t=e.i(244451);e.s(["Spin",()= …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,11751,e=>{"use strict";e.s(["mapEmptyStringToNull",0,function(e){return""===e?null:e}])},643449,e=>{"use strict";var t=e.i(84347 …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,94629,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.createElement("svg",Object.assign({xmlns:"htt …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,599724,936325,e=>{"use strict";var t=e.i(95779),r=e.i(444755),l=e.i(673706),s=e.i(271645);let a=s.default.forwardRef((e,a)=>{let …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,509345,e=>{"use strict";var t,a,l=e.i(843476),r=e.i(271645),i=e.i(464571),s=e.i(326373),n=e.i(653496),o=e.i(755151),d=e.i(646563 …`})]})},tW=({guardrailId:e,onClose:t,accessToken:a,isAdmin:s})=>{let n,[o,d]=(0,r.useState)(null),[g,h]=(0,r.useState)(null),[f,j]=(0,r.useState)(!0),[_,v]=(0,r.useState)(!1),[b]=u.Form.useForm(),[w,N]=(0,r.useState)([]),[C,S]=(0,r.useState …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,664307,e=>{"use strict";var t=e.i(843476),l=e.i(602869),s=e.i(266027),a=e.i(243652),r=e.i(135214);let i=(0,a.createQueryKeys)("c …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,94629,e=>{"use strict";var t=e.i(271645);let r=t.forwardRef(function(e,r){return t.createElement("svg",Object.assign({xmlns:"htt …- Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.`)}function eu(e,t,r,n){if(n.syncDynamicErrorWithStack)throw ei(e,n.syncDynamicErrorWithStack),new l.StaticGenBailoutError;if(0!==t){if(r.has …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,389543,e=>{"use strict";var t=e.i(843476),l=e.i(271645),r=e.i(304967),a=e.i(269200),s=e.i(427612),n=e.i(496020),i=e.i(389083),o= …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,525720,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(529681),s=e.i(908286),l=e.i(242064),n=e.i(246422),i=e. …`]:Object.assign({},{background:e.skeletonLoadingBackground,backgroundSize:"400% 100%",animationName:c,animationDuration:e.skeletonLoadingMotionDuration,animationTimingFunction:"ease",animationIterationCount:"infinite"})}}})((0,u.mergeToken …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,772345,e=>{"use strict";e.i(247167);var t=e.i(931067),a=e.i(271645);let s={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusa …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,525720,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(529681),s=e.i(908286),l=e.i(242064),n=e.i(246422),i=e. …`;t.document.write(a),t.document.close(),t.onload=()=>{t.print()}})(e),a(!1)},children:[(0,t.jsx)(e_.FilePdfOutlined,{className:"mr-3 text-red-500"}),"Export as PDF"]}),(0,t.jsxs)("button",{className:"flex items-center w-full px-4 py-2 text …}'`}),(0,t.jsx)(a.Text,{className:"text-xs text-gray-600 mt-3 mb-2",children:"Look for these headers in the response:"}),(0,t.jsxs)("div",{className:"space-y-1.5",children:[(0,t.jsxs)("div",{className:"flex items-start gap-3",children:[(0,t …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,214541,e=>{"use strict";var t=e.i(271645),a=e.i(135214),s=e.i(270345);e.s(["default",0,()=>{let[e,l]=(0,t.useState)([]),{accessT …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,510674,e=>{"use strict";var t=e.i(266027),s=e.i(243652),a=e.i(602869),l=e.i(431703),r=e.i(135214),i=e.i(708347);let n=(0,s.creat …(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,525720,e=>{"use strict";e.i(247167);var t=e.i(271645),r=e.i(343794),a=e.i(529681),s=e.i(908286),l=e.i(242064),n=e.i(246422),i=e. …Why it matters: Usually legitimate, but confirm the destinations are expected and no sensitive data leaves.
Fix: Confirm the destination hosts are expected and that no sensitive data is sent off-host.
The component makes outbound network requests.
import httpx
import httpx
self.response = response or httpx.Response(
status_code=self.status_code,
request=httpx.Request(method="POST", url="https://litellm.ai"),
)request=httpx.Request(method="POST", url="https://litellm.ai"),
import httpx
response = httpx.get(url, timeout=timeout)
import httpx
response=httpx.Response(
status_code=400,
content="Unsupported provider",
request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
) …request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
response=httpx.Response(
status_code=400,
content="Unsupported provider",
request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
) …request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
response=httpx.Response(
status_code=400,
content="Unsupported provider",
request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
) …request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
response=httpx.Response(
status_code=400,
content="Unsupported provider",
request=httpx.Request(method="delete_assistant", url="https://github.com/BerriAI/litellm"),
),request=httpx.Request(method="delete_assistant", url="https://github.com/BerriAI/litellm"),
response=httpx.Response(
status_code=400,
content="Unsupported provider",
request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
) …request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
response=httpx.Response(
status_code=400,
content="Unsupported provider",
request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
) …request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
response=httpx.Response(
status_code=400,
content="Unsupported provider",
request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
) …request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
response=httpx.Response(
status_code=400,
content="Unsupported provider",
request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
) …request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
response=httpx.Response(
status_code=400,
content="Unsupported provider",
request=httpx.Request(method="create_thread", url="https://github.com/BerriAI/litellm"), # type: ignore
) …Why it matters: Usually legitimate, but confirm the destinations are expected and no sensitive data leaves.
Fix: Confirm the destination hosts are expected and that no sensitive data is sent off-host.
An MCP tool surface (manifest or tool definitions) was found.
Why it matters: Just context — review which tools it offers and their permissions.
Fix: Review the declared MCP tools and their permissions.
Check your own component
Run the same evidence-backed scan on any MCP server, agent skill, or package.
Scan your own componentOr get notified if this component's risk changes:
How we determine this: deterministic static analysis (regex + AST), evidence-anchored, no code execution. Methodology →