top of page

LiteLLM 1.107.0 Compromised: Find It, Rotate Keys, Hunt

Writer: Inception Security
Inception Security
10 minutes ago
15 min read

What this means for your clients: a popular tool that connects business apps to AI services briefly published a new version that steals passwords and keys. Any team that installed a compromised 1.107.0 wheel or ran an infected image should treat that environment as compromised, rebuild it, delete any cached copy and change every key that machine could reach.

 

On the morning of October 21, a developer on your client's team pulled the newest LiteLLM to try a new model. The proxy started and the logs looked normal, but the payload had already run and sent out a copy of every key that machine could read.

 

LiteLLM is an AI gateway. It sits between an application and providers such as OpenAI, Anthropic, Azure and AWS Bedrock, so a single deployment can hold the keys to several of them. On October 21, LiteLLM 1.107.0 shipped on PyPI and Docker with a credential stealer built in. Because this is a supply chain attack rather than a flaw in LiteLLM's code, there is no CVE to patch against. The response is to remove the bad version, rotate every secret it could reach and then hunt for it on other hosts.

 

BerriAI published its root cause on October 23: a master key leaked to a public repository in May, and nobody revoked it. If you run your own gateway, that is the lesson to take home.

 

What was compromised

 

According to the Upwind researcher report in BerriAI's GitHub issue 47826, all seven PyPI wheels of litellm 1.107.0 carry the payload. The sdist has a tampered build file but no payload files. Wiz, citing ClickPy data, puts PyPI downloads at about 49,000. Mirrors and CI caches pull the same wheel over and over, so that is not a count of infected hosts, but it is not small either.

 

Docker got hit too. The bad v1.107.0 tag went out on GHCR for ghcr.io/berriai/litellm, litellm-database and litellm-non_root, and on Docker Hub for docker.io/litellm/litellm, and latest, main-latest and main-stable all pointed at it. BerriAI says Docker Hub served it from 4:46 to 7:20 AM Arizona time on October 21, and GHCR's tags were down by 6:51. If you pulled an unpinned image in that window, check the digest.

 

The issue also lists eleven clean versions, among them 1.106.2 and both 1.107.0 release candidates, so check it if you need to clear one specific build. StepSecurity notes the 1.107.0.dev1 to dev3 builds were not inspected, so treat them as unknown. BerriAI says its private enterprise registry is not affected.

 

PyPI had pulled the wheels earlier, by 6:23 AM. BerriAI resumed releases early on October 24 with 1.103.8, 1.104.6, 1.105.4 and 1.106.3. When we checked Docker Hub that afternoon, latest and main-stable pointed at the v1.106.3 image (we did not recheck GHCR), and BerriAI's director of security wrote in issue 47826 that every image currently in its public registry is legitimate. A tag check still cannot see pull-through mirrors or CI caches that fetched the image during the window.

 

What the stealer takes

 

Three files land in the Python site-packages root: cook.pth, cook.py and sitecustomize.py. Python loads them on every start, so running pip triggers them.

 

Per issue 47826, the stealer collects browser passwords and cookies, SSH, GPG and TLS private keys, shell and database history, cloud and Kubernetes credentials, GitHub, npm and PyPI tokens, .env files, CI and Vault secrets, AI coding tool configs and the environment of every readable process. On a cloud host it grabs the instance role credentials and checks them against AWS.

 

LiteLLM operators should worry most about proxies with a database URL set. On those hosts the stealer dumps the two proxy database tables that store every upstream provider API key.

 

The data is encrypted before it leaves, so a network capture will not show you what went. The issue says to assume exfiltration succeeded on every host with outbound internet that installed 1.107.0. Wiz reports the stolen credentials are already in use. From 9:20 to 10:01 AM Arizona time on October 21, the attacker tested AWS instance role credentials taken from compromised CI runners and Kubernetes nodes, calling sts:GetCallerIdentity and then bedrock:ListFoundationModels and ListModels, a pattern consistent with LLMjacking. The calls came from 168.100.8[.]57 and 165.227.201[.]8.

 

sitecustomize.py also starts a background process that checks a remote file every hour for instructions. Researchers say that file was empty and the account behind it is now deleted, so no command was ever issued. The process keeps polling on infected hosts, so it still has to be killed. On Windows, the loader fails quietly but the stealer still runs.

 

How it got in

 

BerriAI's first story, on October 21, was that the attacker had broken into an internet-facing internal LiteLLM deployment and pulled GitHub CLI tokens out of its logs, and BerriAI suspected a recently patched bug was the way in. The October 23 attack chain post walked that back, and BerriAI's director of security later called the patched bug theory a failure to apply Occam's razor. The real story starts on May 27, when a configuration file holding the master key to an internal LiteLLM Agent Platform deployment was committed to the public LiteLLM-Labs/lite-harness repository. The commit was force-pushed over and the key was marked for revocation, but the revocation never happened.

 

On October 10, from 69.48.229[.]143, the attacker used that key against the Agent Platform API, which returned the configuration of every managed agent. That included a GitHub CLI token belonging to one of BerriAI's two GitHub organization owners. BerriAI says the token was not tied to a service account and was not scoped down, so it gave owner-level access to every repository. The attacker then pushed short-lived branches whose CI workflows posted repository secrets to webhook[.]site, collecting the tokens of two more maintainers and, two days later, secrets from other private repositories. Socket, which BerriAI credits with an independent investigation, says the October 12 run reached provider keys for Anthropic, OpenAI and AWS Bedrock, among others. BerriAI describes those as minimally funded CI testing keys and says it is revoking every token on every internal system and vendor platform.

 

On the morning of October 21, the owner's token was used to override branch protection on the private release repository and point the release workflow at the lookalike repository Berri-AI/litellm. Normally a release must be approved by a special account locked to a physical device in BerriAI's office, but that rule had been relaxed that week so any two engineers could ship bugfix backports. One stolen maintainer token approved the release, and the other deleted the run records afterwards. BerriAI notes that the owner's token could have removed the restriction anyway. This is the second LiteLLM compromise this year, after 1.82.7 and 1.82.8 in March.

 

What to change this week

 

The first job is inventory, which means finding every place LiteLLM runs: developer laptops, notebooks, CI/CD runners, containers and the proxy itself. Check lockfiles for litellm==1.107.0, and look hard at open-ended pins such as litellm>= that resolved on October 21.

 

If you find the bad version on a host, do not use pip to remove it, because any Python start reruns the payload. Preserve the environment and its logs first. Write down when the bad version arrived and which secrets the host could read, because that list drives your rotation. Then, from the shell, kill the background process holding /tmp/remote_code_loader.lock, delete the three files and their cached copies, and rebuild the venv or image from scratch.

 

Pin 1.106.3, or 1.106.2 if you have not moved yet, and pin images by digest rather than tag. Purge 1.107.0 from internal mirrors and caches, and block litellm[.]dev at DNS and egress.

 

One catch: the Docker images and Helm charts for the October 24 releases are signed with a new cosign key from commit e82a3c6, so any cosign verify step, CI check or admission policy still using the old key will reject them. Update the key rather than switching verification off. The clean digests we saw on Docker Hub were sha256:74d0696a9f0afcc993c7659d246f0c542f003368298633e852228250779f1032 for v1.106.3 on October 24 and sha256:7294b90f868c5c38c99b83021c7ba46f9b439e95f8e32964c925c7d2563a03f7 for v1.106.2 on October 21.

 

Then rotate. Start with the instance or task cloud role, since Wiz saw stolen role credentials tested the same morning. Next come the provider keys stored in the proxy database, then the LiteLLM master, salt and virtual keys, the database password and any secret sitting in a process environment on that host.

 

After that come SSH and GPG keys, browser passwords and sessions, GitHub, PyPI and npm tokens, Kubernetes and Vault tokens, CI secrets and AI tool tokens. Give each of these an owner today, and if you are an MSP, use the exercise to map where AI keys live across your clients, including laptops and CI runners.

 

A confirmed hit needs a full incident response. Cleaning the host removes the stealer, but it does nothing about the secrets that already left. Threat hunting then tells you whether it reached hosts nobody remembered, such as a contractor laptop or a CI runner that pulls the latest image on every build.

 

Once the fire is out, look at your own setup if you run a LiteLLM proxy or agent tooling, because BerriAI's root cause is the checklist. Find any master key that was ever committed or pasted somewhere public and confirm it was actually revoked, not just scheduled for it. Replace personal GitHub CLI tokens in automation with narrowly scoped service credentials, and look at which repository secrets a branch push can expose to CI. BerriAI's director of security also endorsed running LiteLLM with default-deny egress, which would have limited what a poisoned release could send out.

 

Hunts to run (test first)

 

These hunts use the IOCs in GitHub issue 47826, StepSecurity, Wiz and BerriAI's incident post, defanged in prose. The addresses in BerriAI's attack chain post, 69.48.229[.]143 and 199.91.221[.]39, were used against BerriAI's own systems, so they are worth a quick look in your logs but are not proof of the stealer on your hosts. Each query is a template, so check field names against your own data first. Search from October 21 onward. A missing marker file proves nothing, because the issue notes one copy of the stealer writes none. The table under the hunts, "Interpret before you escalate", says what is benign and what is not.

 

Hunt 1 on the host: find the package and the files

 

None of these commands start Python, so they will not rerun the payload. They grep lockfiles and requirements for the bad version, including Poetry and uv lockfiles that put the name and version on separate lines. They also look in every site-packages folder for the three payload files and the litellm-1.107.0.dist-info folder BerriAI lists. The last four lines check the lock and marker files in /tmp, show any process holding the lock, list local LiteLLM images with their digests and list the images and image IDs of Kubernetes pods. Images renamed in an internal mirror will not match the grep, so search those by digest.

 

A sitecustomize.py can be legitimate on some distros, so compare its hash against the IOC before you call it hostile. Run these commands as root so they can see every user's venvs. They assume GNU tools; on macOS, use shasum -a 256 in place of sha256sum and install GNU grep for the -P line. If a host ran the proxy only in Docker, an empty result tells you little, so check the image instead.

 

grep -rIil --exclude-dir=proc --exclude-dir=sys --include='requirements*.txt' --include='constraints*.txt' --include='*.lock' --include='pyproject.toml' -E 'litellm(\[[^]]*\])?[[:space:]]*(==[[:space:]]*|=[[:space:]]*")1\.107\.0([[:space:]"#;,]|$)' / 2>/dev/null
grep -rIlzP --exclude-dir=proc --exclude-dir=sys --include='*.lock' 'name[ \t]*=[ \t]*"litellm"\r?\nversion[ \t]*=[ \t]*"1\.107\.0"' / 2>/dev/null
find / -path /proc -prune -o -type f \( -name 'cook.pth' -o -name 'cook.py' -o -name 'sitecustomize.py' \) -path '*-packages*' -exec sha256sum -- {} + 2>/dev/null
find / -path /proc -prune -o -type d -name 'litellm-1.107.0.dist-info' -print 2>/dev/null
ls -la /tmp/remote_code_loader.lock /tmp/.pc_once_* 2>/dev/null
lsof /tmp/remote_code_loader.lock 2>/dev/null
docker images --digests 2>/dev/null | grep -i litellm
kubectl get pods -A -o custom-columns='NAMESPACE:.metadata.namespace,POD:.metadata.name,IMAGES:.spec.containers[*].image,IMAGE_IDS:.status.containerStatuses[*].imageID,INIT_IMAGES:.spec.initContainers[*].image,INIT_IMAGE_IDS:.status.initContainerStatuses[*].imageID' 2>/dev/null | grep -i litellm

 

Match the hashes against these values from issue 47826 and StepSecurity: cook.pth 7f191632e7320705d154b85204f1ae546b543acbd7e8861229b76f5042b92bdb, cook.py 9dd0a3926f96a37eb86cf1ee2310d9be93139cc4ebef3ef9e2efe9531390be25, sitecustomize.py 34bef04fe88ac9d0aae0475630b1738681d15b94f233ac8aa46eacf5968305fa. The Windows copies hash differently, per StepSecurity: cook.pth 84dc8c82c0a4a4a62552ef826b49fcc86d1a5c4a5d0f2c06665723f93d129d7d, cook.py 03ac2a8b752605d1d7710979c17ff18b03dd978203ba23ba97fd8ce3d6f897ea, sitecustomize.py b6122440d0d9cb1eb1ade9933f49214da8c31288de7710c076c2680dfa528465. Infected image index prefixes are 1bbcb1443bc9 (litellm), c00f9d92c427 (litellm-database) and 7b00e91cd2fe (litellm-non_root). Local Docker can show a platform manifest digest instead of the index, so also compare against the litellm amd64 manifest sha256:bd1aeee419ea36da9aa2b657288da4101887be468f020ac63d22ba6ed84a3ea5 and arm64 manifest sha256:56b74573eed6e4aafe4b50603dbe7853e0345f188c8e44a09f1098caf1f4bcdf. BerriAI's incident post gives the full litellm index as sha256:1bbcb1443bc962e45f5aad53fe3d2c30600e0379715fb6c664cdd3ac126c339e. Wiz lists the other variants' platform manifests: litellm-database amd64 sha256:24581ddc30767f16ecb69d2b0517556f2cd7dea56971adb42a3d1beb97d69523 and arm64 sha256:827dd893c74cf621a860a66a3a447a5c732533f087589ce905573e285c0a239c, and litellm-non_root amd64 sha256:645a67d810628252d63df85dcc8824c58bcc77cf8383f4d3e6321f0ccc3ce9e4 and arm64 sha256:f75c8edae59b72b1ebfd617295833f465c85bb2fab9c1d60f21b496db86cb8da. Inspect any image you still cannot match for the payload files.

 

Hunt 2 in Falcon CQL: payload files and attacker DNS

 

Search 1 finds the payload files written into a site-packages folder. Search 2 finds DNS lookups for the attacker domain, litellm[.]dev. The real project domain is litellm.ai, so do not block that one. The table shows aid, which is the sensor ID, so join it to your host lookup to get host names. Falcon may not record every .py write on Linux, so an empty Search 1 is weaker than an empty Search 2.

 

Search 1: payload files

 

regex("Written$", field="#event_simpleName")
| FileName=/^(cook\.pth|cook\.py|sitecustomize\.py)$/i
| TargetFileName=/-packages/i
| table([@timestamp, aid, FileName, TargetFileName, SHA256HashData])

 

Search 2: attacker DNS

 

in(field="#event_simpleName", values=["DnsRequest"])
| DomainName=/(^|\.)litellm\.dev$/i
| table([@timestamp, aid, DomainName, ContextBaseFileName])

 

Hunt 3 in Microsoft Defender KQL: files and connections

 

Search 1 maps the same file names to DeviceFileEvents, where FolderPath holds the full path, including the file name. Search 2 looks in DeviceNetworkEvents for the attacker domain or the dead drop account name, which appears only where the full HTTPS URL is logged. Python makes plenty of normal network connections on developer machines, so a Python process in the results is not suspicious on its own. What matters is a connection to the attacker domain or the dead drop account.

 

Search 1: payload files

 

DeviceFileEvents
| where Timestamp > datetime(2026-10-21T00:00:00Z)
| where FileName in~ ("cook.pth","cook.py","sitecustomize.py") and FolderPath contains "-packages"
| project Timestamp, DeviceName, ActionType, FolderPath, FileName, SHA256, InitiatingProcessFileName

 

Search 2: attacker URLs

 

DeviceNetworkEvents
| where Timestamp > datetime(2026-10-21T00:00:00Z)
| where RemoteUrl has "litellm.dev" or RemoteUrl has "letters9813"
| project Timestamp, DeviceName, RemoteUrl, RemoteIP, InitiatingProcessFileName, InitiatingProcessCommandLine

 

Hunt 4 in Splunk: proxy logs and cloud role use

 

Search 1 looks in web proxy or firewall logs for the domain, the /codepy path, the dead drop account or the stealer's fixed X-Token value XWiA8gZNa7NcX2XRoAEb, which only shows up where headers are logged. The dead drop account name appears only where the proxy inspects HTTPS, because that fetch is encrypted. Search 2 lists CloudTrail GetCallerIdentity calls from assumed roles from October 21 onward, which the stealer makes to test stolen role credentials. This covers role credentials only; to cover access keys taken from environment variables, remove the userIdentity.type filter. Many tools call GetCallerIdentity, so line results up with LiteLLM install times, then look for the same role used from addresses outside your infrastructure. Also look for any calls from 168.100.8[.]57 or 165.227.201[.]8, and for bedrock:ListFoundationModels from the same role soon after GetCallerIdentity. Search 3 finds both. Wiz also saw IAM listing and general discovery calls in some environments, so review every event from those two addresses, not only the Bedrock calls.

 

Search 1: proxy and firewall

 

index=* ("litellm.dev" OR "/codepy" OR "letters9813" OR "XWiA8gZNa7NcX2XRoAEb") earliest="10/21/2026:00:00:00"
| eval src=coalesce(src, src_ip, "unknown")
| stats count min(_time) as first_seen by sourcetype, host, src
| convert ctime(first_seen)

 

Search 2: CloudTrail

 

index=* sourcetype=aws:cloudtrail eventName=GetCallerIdentity userIdentity.type=AssumedRole earliest="10/21/2026:00:00:00" latest=now
| stats count values(sourceIPAddress) as src by userIdentity.arn

 

Search 3: Wiz attacker addresses and Bedrock listing

 

index=* sourcetype=aws:cloudtrail (sourceIPAddress="168.100.8.57" OR sourceIPAddress="165.227.201.8" OR eventName=ListFoundationModels) earliest="10/21/2026:00:00:00" latest=now
| stats count min(_time) as first_seen values(eventName) as events values(sourceIPAddress) as src by userIdentity.arn
| convert ctime(first_seen)

 

Hunt 5 in Elastic: files, DNS and proxy paths

 

These ES|QL searches cover Elastic Defend or other ECS-mapped data. Search 1 finds the three payload files written under a site-packages or dist-packages folder, and Search 2 finds lookups or connections naming the attacker domain or the /codepy path. Index patterns and field names vary by integration, so adjust them to your own data. An empty result only covers hosts that ship file and network events to Elastic.

 

Search 1: payload files

 

FROM logs-endpoint.events.file-*
| WHERE @timestamp >= TO_DATETIME("2026-10-21T00:00:00Z")
| WHERE file.name IN ("cook.pth", "cook.py", "sitecustomize.py")
| WHERE file.path LIKE "*site-packages*" OR file.path LIKE "*dist-packages*"
| KEEP @timestamp, host.name, event.action, file.path, file.hash.sha256, process.name

 

Search 2: attacker domain and /codepy

 

FROM logs-*
| WHERE @timestamp >= TO_DATETIME("2026-10-21T00:00:00Z")
| WHERE dns.question.name == "litellm.dev" OR dns.question.name LIKE "*.litellm.dev" OR url.domain == "litellm.dev" OR url.domain LIKE "*.litellm.dev" OR url.path LIKE "*/codepy"
| STATS hits = COUNT(*), first_seen = MIN(@timestamp) BY host.name, source.ip, process.name

 

Interpret before you escalate

 

What you see

Benign read

When to escalate

litellm 1.107.0 in a lockfile

The file lists it, but no host installed it

If any host installed it, clean that host and rotate its secrets

cook.pth or cook.py in site-packages

An unrelated file using the same name

Confirm it matches the payload; if the bad wheel was installed or an infected image ran, assume reachable secrets were stolen

sitecustomize.py in site-packages

A distro or vendor file

The hash matches the IOC, or nobody can say where the file came from

Lookup of litellm[.]dev

An analyst or security tool checking the domain

Any other lookup: check the requesting process, then look for the payload files on that host

LiteLLM image with an infected digest

None

Purge and replace it, find out whether any container ran it and rotate secrets wherever it ran

A pull of latest, main-latest or main-stable on Oct 21 from 4:46 AM Arizona time until 6:51 AM (GHCR) or 7:20 AM (Docker Hub)

A pull outside that window

Check the pulled digest, and treat any host that ran an infected image as compromised

GetCallerIdentity from a role

Normal tooling

The call lines up with a LiteLLM install, or the same role is later used from outside your network

Empty across all hunts

Nothing matched your data

An empty result does not prove the environment is clean, so confirm that your searches cover developer laptops and CI runners

 

What to alert on (test first)

 

These three rules turn the hunts above into alerts that keep watching new data. Each is a template, so run it as a search for a few days and tune it before you let it page anyone.

 

Alert 1: payload files in site-packages (Falcon, Defender)

 

This rule watches for the three payload files, cook.pth, cook.py and sitecustomize.py, being written anywhere under a site-packages or dist-packages folder. The payload puts them in the root, but the wider match also catches odd layouts.

 

In Falcon, FileName holds the file name and TargetFileName holds the full path. In Defender, FileName holds the file name, FolderPath holds the full path and SHA256 holds the hash to match against the IOCs in Hunt 1.

 

Some distros and vendors ship a legitimate sitecustomize.py, and package installs write files all day, so record the known ones per host and exclude them by full path and hash, never by wildcard. cook.pth and cook.py have no known legitimate use in these folders, but compare their hashes and contents with the published IOCs before you call a host infected.

 

Falcon may not record every .py write on Linux, so judge an empty result against each product's file coverage on that host. Neither sees a container image that was never run on a monitored host.

 

Search 1: Falcon

 

regex("Written$", field="#event_simpleName")
| FileName=/^(cook\.pth|cook\.py|sitecustomize\.py)$/i
| TargetFileName=/(site|dist)-packages/i
| table([@timestamp, aid, FileName, TargetFileName, SHA256HashData])

 

Search 2: Defender

 

DeviceFileEvents
| where ActionType in ("FileCreated","FileRenamed","FileModified")
| where FileName in~ ("cook.pth","cook.py","sitecustomize.py")
| where FolderPath contains "site-packages" or FolderPath contains "dist-packages"
| project Timestamp, DeviceId, DeviceName, ReportId, FolderPath, FileName, SHA256, InitiatingProcessFileName, InitiatingProcessCommandLine

 

Alert 2: egress to litellm[.]dev (Falcon, Defender)

 

The stealer posts its encrypted archive to www[.]litellm[.]dev, per issue 47826. The real project domain is litellm.ai, so the rule anchors on the .dev name and should not touch the real one.

 

In Falcon, DomainName holds the lookup and ContextBaseFileName holds the process that made it. In Defender, RemoteUrl holds the name, while RemoteIP and InitiatingProcessFileName show the address and the caller.

 

Outside investigation work, the domain has no legitimate use, so false positives should be rare. A security tool or analyst checking the domain will still trip it, so note who did it before you isolate.

 

RemoteUrl is often empty for raw IP connections. On a host that sends web traffic through an explicit proxy, the proxy resolves the name, so the host may log no lookup and RemoteUrl may show only the proxy. For those hosts an empty result proves nothing, so check the proxy logs in Hunt 4.

 

Search 1: Falcon

 

in(field="#event_simpleName", values=["DnsRequest"])
| DomainName=/(^|\.)litellm\.dev$/i
| table([@timestamp, aid, DomainName, ContextBaseFileName])

 

Search 2: Defender

 

DeviceNetworkEvents
| where RemoteUrl has "litellm.dev"
| project Timestamp, DeviceId, DeviceName, ReportId, RemoteUrl, RemoteIP, RemotePort, InitiatingProcessFileName, InitiatingProcessCommandLine

 

Alert 3: /codepy fetches (Splunk)

 

The background loader would fetch a /codepy path from whatever domain the remote file named, per issue 47826 and StepSecurity, so the host is unknown in advance and the path is the signal.

 

Search 1 uses the CIM Web data model, so it needs proxy or firewall data mapped to CIM, with uri_path holding the request path. Search 2 is a raw search for proxies that are not CIM mapped.

 

Researchers say no command was ever issued, so a hit is unlikely. If you get one, an unrelated site may use the same path, so rule that out first. Otherwise, any hit means a host ran the payload and reached the attacker's server, so confirm the payload files on that host first.

 

The loader would fetch /codepy over plain HTTP, so any proxy that logs URLs could see it, but an empty result covers only traffic that passed through a logging proxy.

 

Search 1: CIM Web

 

| tstats count min(_time) as first_seen from datamodel=Web where Web.uri_path="*/codepy" by Web.src Web.dest Web.url
| convert ctime(first_seen)

 

Search 2: raw proxy logs

 

index=* "/codepy"
| eval src=coalesce(src, src_ip, "unknown")
| stats count min(_time) as first_seen by sourcetype, host, src
| convert ctime(first_seen)

 

What This Means for Your Team

 

Start today by finding every LiteLLM install and image. Clean affected hosts without starting Python, pin litellm 1.106.3 (or 1.106.2 if you have not moved yet) and pin images by digest. Then rotate every key those hosts could see, beginning with the provider keys in the proxy database, and check that any key you ever exposed was truly revoked. After rotation, run the hunts, and treat an empty result on an unmonitored dev laptop as a coverage gap.

 

Sources

 

 

Inception Protection

 

Inception Protection is the Inception Security managed detection and response service, and it works with the Microsoft licenses you already have. We watch Defender and sign-in data in your Microsoft environment, dig into anything odd and work through containment with your team. Developer tooling and cloud keys outside that environment stay with your team.

 

Inception Foresight

 

Stolen keys rarely stay in one place. A GitHub token or cloud role taken from a dev box can lead back to Microsoft 365 through shared passwords and app registrations. To find out whether your Microsoft environment would catch that kind of activity, try the free Inception Foresight M365 Assessment: https://www.inceptionsecurity.com/m365assessment.

 

bg-map-white.png

INCEPTION SECURITY™

A cybersecurity company with in depth knowledge of the threat landscape and security controls.

NAVIGATION

GET IN TOUCH

© 2025 All Rights Reserved by INCEPTION SECURITY™ .

bottom of page