中文版正在随流水线自动整理,稍后刷新即可;可先阅读下方英文原文。
本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。
AI图鉴首页 › AI 资讯 › PHP2Shell, LiteLLM, GitLab:找到需要补丁的东西
文章 URL:https://cloudsleuth.io/blog/php2shell-litellm-gitlab-find-What-you-run/ 评论 URL:https://news.ycombinator.com/item?id=50261583 点:16#Co
中文版正在随流水线自动整理,稍后刷新即可;可先阅读下方英文原文。
本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。
Between October 16 and 23, 2026, PHP, Node.js, GitLab, LiteLLM, OpenCode and the eMudhra certificate authority all had serious security incidents. PHP, Node.js and GitLab shipped fixes on October 21, the same day the bad LiteLLM release went out. Every advisory ended with some version of upgrade, rebuild or rotate.
Doing the upgrade is the easy part. What takes time is working out, for your own accounts, where the affected thing runs, who owns it, and what it can reach. If you have an inventory you trust, that’s an afternoon. If you don’t, it’s a week of Slack threads, and this week didn’t give anyone a week. Amazon’s MadPot honeypots logged a PHP2Shell exploit attempt four days before the bugs were disclosed.
The week’s incidents
Nothing on that list is obscure. Two are runtimes that a large share of the web sits on, one is the source-control server plenty of companies still host themselves, and one is the AI gateway a lot of teams adopted in a hurry to route LLM traffic. If you run a reasonably sized estate on AWS or Azure, at least one of these was probably yours to deal with.
The exploit window keeps getting shorter
Mandiant tracks how long attackers take to exploit a vulnerability after disclosure. Its time-to-exploit analysis put the average at 63 days in 2018–2019, 44 days in 2020–2021 and 32 days in 2021–2022. In 2023 it was five days, and 70% of the exploited vulnerabilities Mandiant tracked that year were zero-days, exploited before a patch existed.
Drew Silcock’s post Is this the new cyber normal?, which reached the front page of Hacker News on October 23, argues that LLMs have compressed this further, so the gap between a bad RCE becoming public and automated attacks against it is now hours rather than weeks. PHP2Shell fits. The bugs were found with help from an AI model, patched binaries appeared before the advisory after an embargo dispute, and exploit attempts started before most people could install the fix.
Your exposure window is the time to find what’s affected plus the time to fix it. Most teams have spent years shrinking the second number with CI/CD, managed runtimes and automatic patching. The first number is still a spreadsheet, a Slack thread, and whoever remembers how the old GitLab box was set up.
This is why the frameworks put inventory first. The CIS Controls make inventory of enterprise assets and inventory of software Controls 1 and 2; vulnerability management doesn’t show up until Control 7. CISA’s BOD 23-01 requires US federal agencies to run automated asset discovery every seven days and vulnerability enumeration every 14. If you don’t know a server exists, you won’t patch it.
Working through an advisory with native tools
Here is how I’d answer each of those questions with what AWS and Azure give you out of the box, using this week’s incidents as examples. Every command below is read-only.
1. Where it runs
Start with Node.js. On Lambda, supported managed runtimes get runtime updates automatically by default, so most functions on a current Node.js runtime pick up the fix without a redeploy. Two groups don’t. Functions on the deprecated nodejs20.x runtime stopped getting security patches when Node.js 20 reached end of life in April 2026. Functions deployed as container images carry whatever Node.js was baked into the image. So what you actually need is the list of functions on an old runtime or packaged as an image:
# Node.js and container-image Lambda functions in every enabled region
for region in $(aws ec2 describe-regions --query "Regions[].RegionName" --output text); do
echo "== $region"
aws lambda list-functions --region "$region" \
--query "Functions[?PackageType=='Image' || (Runtime && starts_with(Runtime, 'nodejs'))].[FunctionName, Runtime || PackageType]" \
--output text
done
Image-based functions are in that output because the Lambda API can’t tell you what’s inside them. For those you need your image scanner, or a rebuild.
For PHP2Shell on Azure, App Service records each Linux app’s runtime stack, and Azure Resource Graph can search it across every subscription you can read:
az graph query -q "
resources
| where type =~ 'microsoft.web/sites'
| mv-expand setting = properties.siteProperties.properties
| where setting.name =~ 'LinuxFxVersion' and tostring(setting.value) startswith 'PHP'
| project name, resourceGroup, subscriptionId, stack = tostring(setting.value)
" --first 1000 -o table
Anything on PHP 8.1 or older gets no regular upstream fix, so put it at the top of the list.
VMs and containers are harder, because the cloud control plane doesn’t know what’s installed on them. That’s what AWS Systems Manager Inventory, Amazon Inspector and Microsoft Defender for Cloud are for, and each one only sees the machines it’s enabled on. That coverage gap is the one that hurts most, and I’ll come back to it.
2. Whether the internet can reach it
GitLab patched GitLab.com itself. Self-managed instances are on you, and short of upgrading there’s no workaround. The one that worries me is rarely the GitLab the platform team runs. It’s the one some team stood up in 2019, or the one that came along with an acquisition, still answering on 443.
Search by name and tag first, then look at exposure:
# Instances that look like GitLab, with public IPs and security groups
aws ec2 describe-instances \
--filters "Name=tag:Name,Values=*gitlab*,*GitLab*" \
--query "Reservations[].Instances[].[InstanceId, State.Name, PublicIpAddress, join(',', SecurityGroups[].GroupId)]" \
--output text
# Security groups with an inbound rule open to the whole internet
aws ec2 describe-security-groups \
--filters Name=ip-permission.cidr,Values=0.0.0.0/0 \
--query "SecurityGroups[].[GroupId, GroupName, VpcId]" \
--output text
In Azure, az vm list -d --query "[?contains(name, 'gitlab')].{name:name, rg:resourceGroup, ips:publicIps}" -o table gets you the same first pass.
Be careful with what this tells you. A name filter only finds servers someone named honestly, and an instance with no public IP can still be reachable through a public load balancer. Both make this hard to answer from the console in the middle of an incident. It’s much easier if you already have an inventory that holds the relationships.
3. Who owns it
Once you’ve found the server, somebody has to approve the downtime, and ideally that person knows how it was installed. Tags are the first place to look. If there aren’t any, CloudTrail can tell you who created the resource:
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=ResourceName,AttributeValue=i-0abc123example \
--query "Events[].[EventTime, EventName, Username]" \
--output table
Event history only goes back 90 days, and the same is true of the Azure Activity Log. For a server from 2019 you need your trail in S3 and an Athena query, which Who Created This AWS Resource? walks through. Even then the creator may have left. In one case we looked at, 89 idle Azure VMs came from an acquisition and nobody on the current team could say what they were for. Resources like that are exactly where an unpatched GitLab ends up living.
4. What it can reach
LiteLLM shows why a package finding is only the start. According to Microsoft’s analysis, the malicious release went after AWS, Azure and Google Cloud credential caches, Kubernetes service-account files, Docker configuration and mounted secrets. It also tried to pull credentials from the AWS and GCP metadata services, and on proxy hosts it read provider keys out of LiteLLM’s own database.
The bad package is what the scanner reports. What you actually have to respond to is the identity the host ran as. For every environment that installed 1.107.0, find the role it had and what that role is allowed to do:
# The instance profile behind an EC2 instance
aws ec2 describe-instances --instance-ids i-0abc123example \
--query "Reservations[].Instances[].IamInstanceProfile.Arn" --output text
# The role inside that profile, and the policies attached to it
aws iam get-instance-profile --instance-profile-name litellm-proxy \
--query "InstanceProfile.Roles[].RoleName" --output text
aws iam list-attached-role-policies --role-name litellm-proxy-role
aws iam list-role-policies --role-name litellm-proxy-role
On ECS the identity is the task role in the task definition. On EKS it’s the role mapped to the pod’s service account. Microsoft’s guidance is to investigate from a clean machine, rebuild from verified artifacts, rotate every reachable credential, and pin container images by digest instead of floating tags like latest. I’d underline the clean-machine part: their analysis says the payload runs when Python starts, so running pip inside a suspect environment to check for the package can trigger it.
5. Where else the secret or certificate lives
OpenCode told users to revoke and reissue the exposed keys. Revoking takes a click. Working out what breaks when you do is the real job, because AI provider keys end up in Secrets Manager or Key Vault, in Lambda and App Service settings, in CI variables and in developers’ .env files. On AWS, Secrets Manager at least records when each secret was last read and last rotated, and CloudTrail’s GetSecretValue events show which roles read it:
aws secretsmanager list-secrets \
--query "SecretList[].[Name, LastAccessedDate, LastRotatedDate]" \
--output table
eMudhra raises the same problem for certificates. With a private key that small, anyone could compute it and sign certificates that browsers would have trusted until the intermediates were blocked. Two checks are worth running. First, search the certificates you’ve imported for eMudhra or emSign issuers. ACM is regional, and certificates used by CloudFront live in us-east-1, so run this in every region you use, us-east-1 included:
for arn in $(aws acm list-certificates \
--includes keyTypes=RSA_2048,RSA_3072,RSA_4096,EC_prime256v1,EC_secp384r1,EC_secp521r1 \
--query "CertificateSummaryList[].CertificateArn" --output text); do
aws acm describe-certificate --certificate-arn "$arn" \
--query "Certificate.[DomainName, Issuer, Type]" --output text
done | grep -i -E "emudhra|emsign"
In Azure, Resource Graph covers App Service certificates across subscriptions:
az graph query -q "
resources
| where type =~ 'microsoft.web/certificates'
| where tostring(properties.issuer) contains 'emSign' or tostring(properties.issuer) contains 'eMudhra'
| project name, resourceGroup, subscriptionId, issuer = tostring(properties.issuer), expires = properties.expirationDate
" -o table
Second, software with its own trust store keeps trusting a CA until that store is updated. Old AMIs, base images and runtimes that bundle their own CA list are where a blocked chain keeps working long after browsers have dropped it.
Where scanners and consoles stop
Amazon Inspector and Defender for Cloud are good at telling you whether a package version on a given machine is vulnerable. The AWS and Azure consoles are good at telling you what’s in one account in one region. Neither is what you need the morning an advisory lands.
The first problem is coverage. A scanner sees the accounts, subscriptions and machines it’s been enabled on, and the GitLab server from the acquisition is usually sitting in the account nobody onboarded. The second is ownership. Findings land in a shared queue where nobody has the authority to restart someone else’s server, so they sit there. A finding with no owner attached is just one more alert. The third is context. The scanner says the package is bad. It doesn’t say the host’s role can read every S3 bucket in the account, or that three other teams’ services call it. With LiteLLM, that context was most of the incident.
What fills those gaps is an inventory that stays current and records what exists, who owns it and how it connects to everything else. That’s the thing we’re building Cloud Sleuth to be.
What this looks like in Cloud Sleuth
Cloud Sleuth maps your AWS and Azure resources, assigns an owner to each one whether it’s tagged or not, and keeps both
Auto-fetched and translated by AI Atlas. All rights belong to the original author.
Blumify:音频语音方向的 AI 工具,Hacker News 新品(热度 90)。
BreadcrumbBreadcrumb:效率方向的 AI 工具,Hacker News 新品(热度 32)。
HandwiredHandwired:编程开发方向的 AI 工具,Hacker News 新品(热度 25)。
L.O.S.S. AIL.O.S.S. AI:效率方向的 AI 工具,Hacker News 新品(热度 25)。
开源项目免费 VPS(无限流量)
InstaBox5 台免费云电脑(每台 4 vCPU/8GB)
E2BAgent 沙箱:注册送 $100 赠金
DaytonaAgent 沙箱:注册送 $200 算力
Hacker News · 10-28
警方正在利用人工智能拦截驾驶员的可疑行为Hacker News · 10-28
28岁的DOGE Operation Gusted USAID. HR没有他在那里工作的记录Hacker News · 10-28
在Lean正规化的有限简易团体分类Hacker News · 10-28
我们让我们的云 agents 查询 prod(有 OIDC,不是秘密)Hacker News · 10-28
Anthropic就非法获得的斯坦福教授书籍培训ClaudeHacker News · 10-27
标题、摘要与正文均来自该信源的公开页面,版权归原作者所有;本站自动聚合与翻译,仅作出处跳转。