<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Khushi Trivedi</title>
    <description>The latest articles on DEV Community by Khushi Trivedi (@trivedi-khushi).</description>
    <link>https://dev.to/trivedi-khushi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1358087%2Fa2429c02-d5b4-4b76-8b99-59ddb2039c8d.png</url>
      <title>DEV Community: Khushi Trivedi</title>
      <link>https://dev.to/trivedi-khushi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/trivedi-khushi"/>
    <language>en</language>
    <item>
      <title>When AI Agent adds Package, Who Approves That Dependency?</title>
      <dc:creator>Khushi Trivedi</dc:creator>
      <pubDate>Mon, 02 Nov 2026 23:30:44 +0000</pubDate>
      <link>https://dev.to/trivedi-khushi/when-ai-agent-adds-package-who-approves-that-dependency-4oah</link>
      <guid>https://dev.to/trivedi-khushi/when-ai-agent-adds-package-who-approves-that-dependency-4oah</guid>
      <description>&lt;p&gt;The review meeting started the way they all do: a timeline on the screen and a question nobody wanted. Who approved that dependency? We traced the package back through git blame to a pull request titled "Add retry logic." An AI coding agent had written it, a teammate had skimmed it, and the approval said "LGTM." The code change was forty lines. The lockfile diff underneath it was longer than the code, and one new package sat in the middle of it.&lt;/p&gt;

&lt;p&gt;Nobody had been careless in the way we usually mean. The author was a tool, the reviewer read the logic, and the dependency arrived as a side effect. That is the gap this post is about. Our process had a place for approving code and no place for approving a decision to trust a stranger's package.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe5w0cp2rwhntp15alt0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe5w0cp2rwhntp15alt0u.png" alt="A pull request approved with LGTM: a short code change beside a longer lockfile diff with one unreviewed new package highlighted." width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  AI-generated dependency changes slip through because they are small, noisy and trusted
&lt;/h2&gt;

&lt;p&gt;Three habits make them easy to miss. Reviewers read the logic and scroll past manifests and lockfiles, which are long and machine-shaped. Agents tend to make many small dependency edits, and a commenter in a &lt;a href="https://reddit.sentinel-team.org/posts/1t0ltr5/snapshots/2026-05-02T04%3A50%3A06.954017Z" rel="noopener noreferrer"&gt;Reddit thread on dependency checking&lt;/a&gt; said the risk is highest exactly there, where humans skim. And agents can install packages themselves: &lt;a href="https://aikido.dev/blog/slopsquatting-ai-package-hallucination-attacks" rel="noopener noreferrer"&gt;Aikido notes&lt;/a&gt; autonomous installs, such as in bypass modes or CI with broad npm permissions, skip the human check) that autonomous installs, such as in bypass modes or CI with broad npm permissions, skip the human check entirely.&lt;/p&gt;

&lt;p&gt;The result is a quiet shift in who makes the trust decision. It used to be a person typing &lt;code&gt;npm install&lt;/code&gt; and thinking about it for a moment. Now it can be a model, a diff and a rubber stamp.&lt;/p&gt;

&lt;p&gt;Here's an interesting short-video I found:&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/MYJ2M9NPKac" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The research shows assistants invent packages often enough to matter
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://arxiv.org/html/2406.10279v1" rel="noopener noreferrer"&gt;A study of 576,000 code samples&lt;/a&gt; across 16 models found that 19.7% of recommended packages did not exist, and 43% of the hallucinated names reappeared in every one of ten reruns. This is based on this &lt;a href="https://socket.dev/blog/slopsquatting-how-ai-hallucinations-are-fueling-a-new-class-of-supply-chain-attacks" rel="noopener noreferrer"&gt;blogpost that I came across&lt;/a&gt;. A name that repeats is a name an attacker can plan around. Bar Lanyado of &lt;a href="https://www.lasso.security/blog/ai-package-hallucinations" rel="noopener noreferrer"&gt;Lasso Security&lt;/a&gt;registered an empty package under a hallucinated name and watched it collect more than 30,000 downloads in three months.&lt;/p&gt;

&lt;p&gt;Agent workflows add a twist. The name &lt;code&gt;react-codeshift&lt;/code&gt; first appeared in one commit of 47 LLM-generated agent skills and spread to 237 repositories before a researcher claimed it. To be fair, those experiments were benign and I know of no confirmed in-the-wild attack of this kind. But a review process that cannot catch a harmless invented name will not catch a hostile one either.&lt;/p&gt;

&lt;h2&gt;
  
  
  Governance means making the dependency decision a named, required, automated step. This is how it's done:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Start with ownership.
&lt;/h3&gt;

&lt;p&gt;A &lt;a href="https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners" rel="noopener noreferrer"&gt;CODEOWNERS file&lt;/a&gt; automatically requests review from the right people when a pull request touches their files, and patterns like &lt;code&gt;**/package.json&lt;/code&gt; and &lt;code&gt;*.lock&lt;/code&gt; can route every manifest and lockfile change to a platform or security team. Then make that review mandatory. In &lt;a href="https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches" rel="noopener noreferrer"&gt;branch protection&lt;/a&gt;, you can require pull requests, require approvals, dismiss approvals when new commits are pushed, and require review from code owners. The stale-approval setting matters for agents, because an approval given before the agent pushed a new commit cannot quietly cover a dependency added afterwards.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Automate the Evidence:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review" rel="noopener noreferrer"&gt;GitHub's dependency review&lt;/a&gt; shows added, removed and updated dependencies on the pull request, including indirect ones from lockfiles, along with release dates. The dependency review action fails by default on known vulnerabilities, and you can make it a required check. Be clear about its limit: a brand-new squatted package has no advisory yet, so a human still has to read the release date and ask why the package exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Puposely enable Cooldown Option:
&lt;/h3&gt;

&lt;p&gt;For instance, &lt;a href="https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference" rel="noopener noreferrer"&gt;Dependabot's cooldown option&lt;/a&gt; basically delays version updates by a configurable number of days (3 by default if you set it without a value), and security updates bypass it. Treat agent-initiated installs as privileged actions, and consider a mirror or allowlist so only vetted packages are reachable, as &lt;a href="https://www.theregister.com/2025/04/12/ai_code_suggestions_sabotage_supply_chain/" rel="noopener noreferrer"&gt;Seth Larson&lt;/a&gt; has suggested for PyPI.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in it for the reviewers?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Well, the reviewers should treat every new dependency as its own decision, with its own answers.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1k4bp6kbazp9hh30rxef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1k4bp6kbazp9hh30rxef.png" alt="Checklist of five questions to answer before approving a new dependency." width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a pull request touches a manifest, we now stop reviewing the code and review the choice. Who suggested this package, a person or the assistant, and why do we need it at all? Does the name match the install command in the project's own documentation? Who publishes it, how old is it, and does the linked repository belong to the real project? Does it run scripts at install time? And does the lockfile diff contain only the packages we expect, or did a single addition pull in a long tail?&lt;/p&gt;

&lt;p&gt;A Reddit commenter offered advice that fits perfectly here: run the checking tool &lt;a href="https://reddit.sentinel-team.org/posts/1t0ltr5/snapshots/2026-05-02T04%3A50%3A06.954017Z" rel="noopener noreferrer"&gt;right after an agent changes dependencies, before install or merge&lt;/a&gt;, and combine signals such as name distance, package age and maintainer changes rather than trusting one. If the answers are thin, the pull request waits.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in it for the template writers here?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Template writers should ask for a justification, and advisory readers should trace who added the package&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you own the pull request template, add a short section for dependencies: each new package, its registry link, why it is needed, and whether an assistant suggested it. That turns a silent side effect into a sentence someone has to write and someone else has to read. It also gives incident reviews like ours an answer to "who approved that?" in the first minute.&lt;/p&gt;

&lt;p&gt;If you read advisories, the same trail helps in reverse. When an advisory names a package, search your lockfile history and pull requests to see when it arrived, who added it, and through which path, direct or transitive. Remember too that Dependabot's cooldown applies to version updates, not security updates, so an urgent fix can still arrive immediately and deserves a faster, but still human, review.&lt;/p&gt;

&lt;h2&gt;
  
  
  The End Goal is a Paper Trail for Every Dependency
&lt;/h2&gt;

&lt;p&gt;Our next review went differently. The agent proposed a package, the template asked why, a code owner looked at the release date and the publisher, and the dependency review check showed the lockfile change in plain sight. Someone's name was on the approval, with a reason next to it. Nothing about that slowed us down by more than a few minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want a wider view:&lt;/strong&gt; of why vetting matters before any of this, &lt;a href="//**https://www.cleanstart.com/blogs/what-is-typosquatting-attacks-examples-and-ai-risks**"&gt;CleanStart's primer on typosquatting attacks&lt;/a&gt;, examples and AI risks notes that OWASP recommends verifying AI-suggested dependencies rather than accepting them at face value. &lt;/p&gt;

&lt;p&gt;Hope your enjoyed reading!❤️&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>ai</category>
      <category>supplychainsecurity</category>
      <category>devsecops</category>
    </item>
    <item>
      <title>The 60-Second Check Before Every npm install</title>
      <dc:creator>Khushi Trivedi</dc:creator>
      <pubDate>Mon, 19 Oct 2026 15:32:41 +0000</pubDate>
      <link>https://dev.to/trivedi-khushi/the-60-second-check-before-every-npm-install-2bg</link>
      <guid>https://dev.to/trivedi-khushi/the-60-second-check-before-every-npm-install-2bg</guid>
      <description>&lt;h2&gt;
  
  
  One wrong package name can run attacker code on your laptop or CI
&lt;/h2&gt;

&lt;p&gt;Honestly, I'd say &lt;code&gt;npm install&lt;/code&gt; is the riskiest five seconds of your day now that typosqatting is so common. It's the potential moment a attacker's code gets a chance to run on your laptop or your CI runner.&lt;/p&gt;

&lt;p&gt;This is not theoretical anymore. It has happened several time, at a huge scale! Some incide&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In &lt;strong&gt;2017, The Slovak National Security Office&lt;/strong&gt; flagged ten fake Python packages. One fake package was &lt;code&gt;urllib&lt;/code&gt;,instead of &lt;code&gt;urllib3&lt;/code&gt;.&lt;br&gt;
They also collected the system's data! &lt;a href="https://news.sophos.com/en-us/2017/09/19/pypi-python-repository-hit-by-typosquatting-sneak-attack/" rel="noopener noreferrer"&gt;news link&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;npm's official record listed 13 releases of a fake package&lt;/strong&gt; called &lt;code&gt;crossenv&lt;/code&gt; for the real pkg &lt;code&gt;cross-env&lt;/code&gt;. Funfact if you today run &lt;code&gt;npm view crossenv&lt;/code&gt;, it returns &lt;code&gt;0.0.2-security&lt;/code&gt;. This is apparantly a placeholder npm put in its place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;19.7% AI generated code samples had package names that doesn't exist.&lt;/strong&gt; Yes, in 2025 USENIX Security study checked 2.23 million AI-generated code samples. If I were an atatcker, I'd register those names and wait. This is called &lt;a href="https://labs.cloudsecurityalliance.org/research/csa-research-note-slopsquatting-ai-supply-chain-20260419/" rel="noopener noreferrer"&gt;slopsquatting.&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After reading about these attacks, I'd the first thing is to have my own investigation. Here are my findings. Enjoy the blog further:&lt;/p&gt;

&lt;h2&gt;
  
  
  How to confirm a package is the one you meant, step by step
&lt;/h2&gt;

&lt;p&gt;This is for developers, SREs, DevOps engineers, and the people who review their pull requests. Run these before you add a package you have not used before:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Exact spelling and ecosystem&lt;/strong&gt;&lt;br&gt;
Read the name letter by letter against the project's own docs. Then ask the registry if it exists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm view cross-env name version
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; pip index versions requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*&lt;em&gt;A missing name returns &lt;code&gt;E404&lt;/code&gt; on npm, or &lt;code&gt;No matching distribution found&lt;/code&gt; on pip. *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Publisher and repo link&lt;/strong&gt;&lt;br&gt;
Check who owns the package. Then check where it says its code lives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm view cross-env maintainers repository.url
&lt;span class="c"&gt;# maintainers = 'kentcdodds &amp;lt;me@kentcdodds.com&amp;gt;'&lt;/span&gt;
&lt;span class="c"&gt;# repository.url = 'git+https://github.com/kentcdodds/cross-env.git'&lt;/span&gt;

curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://pypi.org/pypi/requests/json | python3 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"import sys,json; i=json.load(sys.stdin)['info']; print(i['version'], i['project_urls'])"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** 3. The Package age and publish history **&lt;/p&gt;

&lt;p&gt;You can use this to check about the package's record-&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm view cross-env time.created time.modified
&lt;span class="c"&gt;# time.created = '2015-10-01T23:19:27.453Z'&lt;/span&gt;

npm view cross-env &lt;span class="nb"&gt;time

&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://pypi.org/pypi/requests/json | python3 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"import sys,json; r=json.load(sys.stdin)['releases']; print(min(f['upload_time_iso_8601'] for v in r.values() for f in v))"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The red flags would be spotted if: (a) it's been created recently, but has a famous name (b)there's a new maintainer on an old package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Weekly downloads vs. the real project&lt;/strong&gt;&lt;br&gt;
Another interesting thing that you can do while patrolling is to compare the lookalike with the project it resembles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://api.npmjs.org/downloads/point/last-week/cross-env
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://pypistats.org/api/packages/requests/recent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Low count, new package =&amp;gt; normal. &lt;br&gt;
Low count, fake package for a famous name =&amp;gt; suspicious.&lt;/p&gt;

&lt;p&gt;For your example: &lt;code&gt;pypistats&lt;/code&gt; excludes known mirrors and updates once a day. (Ref: &lt;a href="https://pypistats.org/api/" rel="noopener noreferrer"&gt;PyPI Stats API&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Install scripts&lt;/strong&gt;&lt;br&gt;
Here's my observation. Many legitimate packages have a script. I understood this from the hidden install scripts are &lt;a href="https://snyk.io/blog/sha1-hulud-npm-supply-chain-incident/" rel="noopener noreferrer"&gt;how the September 2025 Shai-Hulud worm ran its code&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm view esbuild scripts.postinstall
&lt;span class="c"&gt;# node install.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Lockfile diff&lt;/strong&gt;&lt;br&gt;
One new dependency can pull in many. As a developer, you must never skip reading what changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff origin/main &lt;span class="nt"&gt;--&lt;/span&gt; package-lock.json

&lt;span class="c"&gt;# only new install scripts&lt;/span&gt;
git diff origin/main &lt;span class="nt"&gt;--&lt;/span&gt; package-lock.json | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'^\+.*"hasInstallScript"'&lt;/span&gt;

&lt;span class="c"&gt;# for a version bump, see what changed in the code&lt;/span&gt;
npm diff &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pkg@1.0.0 &lt;span class="nt"&gt;--diff&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pkg@1.0.1 &lt;span class="nt"&gt;--diff-name-only&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for names you did not expect, and any added "hasInstallScript": true. For Python, do the same with git diff requirements.txt. &lt;a href="https://docs.npmjs.com/cli/v11/commands/npm-diff" rel="noopener noreferrer"&gt;npm diff docs&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the limitations for these six checks
&lt;/h2&gt;

&lt;p&gt;They're merely the checks, but do not really make any install "safe". These are the following limitations:&lt;/p&gt;

&lt;p&gt;• A real package published by a real maintainer whose account was compromised will pass all six checks.&lt;br&gt;
• A lockfile poisoned before anyone noticed will look normal in a diff.&lt;br&gt;
• Malicious code that lives in a package's runtime JavaScript, not in an install script, is not stopped by ignore-scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resouces
&lt;/h2&gt;

&lt;p&gt;I came across this blog- &lt;a href="https://www.cleanstart.com/blogs/what-is-typosquatting-attacks-examples-and-ai-risks" rel="noopener noreferrer"&gt;What Is Typosquatting? Attacks, Examples, and AI Risks.&lt;/a&gt; by CleanStart.&lt;/p&gt;

&lt;p&gt;In this, you can checkout the for the org-level version of this checklist. &lt;/p&gt;

&lt;p&gt;It's also my first blog here. Please share your love in comments!❤️&lt;/p&gt;

</description>
      <category>typosquatting</category>
      <category>cybersecurity</category>
      <category>npm</category>
      <category>containersecurity</category>
    </item>
  </channel>
</rss>
