Claude Code stores approved shell commands in a local settings file inside your project directory. If that project is an npm package, there is a good chance that file is shipping to the public registry with your credentials inside it.
We built a scanner to measure how common this is and to examine what ends up in those files. This post covers how the exposure occurs, what we found, and how to prevent it.
This research was inspired by a LinkedIn post from Kirill Efimov, who first spotted -bc-.claude/settings.local.json-bc- files appearing inside published npm packages. We wanted to expand on this to understand the true scale of the issue and raise awareness of it.
How Claude Code's Permission Model Works
Claude Code operates with a permission system for shell commands. When Claude wants to run a command it has not been permitted to run before, it presents you with options, one of which is "allow always". Choosing this writes the exact command string, to .claude/settings.local.json as a permanent allowlist entry. Claude will not ask about that command again.
The file lives in -bc-.claude/-bc- at the root of your project directory. It looks something like this:
Every command you permanently approve gets recorded there, including any credentials that were inline at the time. A -bc-curl-bc- call with an -bc-Authorization-bc-header. An environment variable like -bc-API_KEY=abc123-bc- prepended to a command. All of it ends up in the file, and the file ends up in your project directory.
The npm Publishing Gap
npm packages are built from the contents of your project directory. Files are excluded via -bc-.npmignore-bc- or the -bc-files-bc- field in package.json, but neither has a default entry for -bc-.claude/-bc-. There is no warning during -bc-npm publish-bc- if the directory is present. The settings file is a hidden dotfile that does not stand out in any part of the normal publish workflow.
-bc-.claude/settings.local.json-bc- follows the same convention as -bc-.env-bc-. The -bc-.local-bc- suffix signals that the file is personal and environment-specific. Unlike -bc-.env-bc-, it does not benefit from widespread awareness or tooling that flags it before it ships.
What We Built
We wrote a TypeScript service that monitors the npm registry's CouchDB changes feed. For every new or updated package, it fetches the tarball and inspects its contents. When a -bc-.claude/settings.local.json-bc- is present, the file is extracted and saved for analysis.
The Findings
Across approximately 46,500 packages monitored over our scan window, 428 contained a -bc-.claude/settings.local.json-bc-. Of those, 33 files across 30 packages contained credentials. Roughly one in thirteen settings files that shipped contained something sensitive.
What Was Inside
-db1-
- npm authentication tokens used to publish packages to the npm registry
- npm login credentials in plaintext: username, password, and email address concatenated into a single allowlist entry
- GitHub personal access tokens, including both fine-grained PATs and classic PATs
- Telegram Bot API tokens, which grant full control of the associated bot: reading messages, sending messages, and all other bot API operations
- Production bearer tokens for third-party services
- Hugging Face API tokens
- Plaintext test credentials: email and password pairs embedded in curl commands used to provision local development accounts-db1-
Why This Is Easy to Miss
The file is not obviously sensitive: it reads as a list of shell commands, and nothing in the publish workflow surfaces it. Most developers never open it.
Credentials end up in allowlist entries naturally. During active development with Claude Code, you approve a lot of commands. Most are harmless. But some involve authenticated API calls, deployment scripts, or service logins. Hit "allow always" instead of "allow once" on any of those, and they go into the file permanently.
Prevention
Add -bc-.claude/-bc- to your -bc-.npmignore-bc-:
If you use the -bc-files-bc- field in -bc-package.json-bc- to control what gets published, -bc-.claude/-bc- will not be included by default, but double-check before you publish.
Add it to -bc-.gitignore-bc- as well. The file has no place in version control:
Check what your next publish will include:
Check versions you have already published:
The Same Problem Exists Beyond npm
npm is the registry we scanned, but the underlying issue applies to any packaging workflow that assembles files from your repository into a publishable archive.
PyPI
Python packages are published as source distributions (sdists) and/or wheels. What gets included depends on the build backend and its file-selection rules. With setuptools, -bc-MANIFEST.in-bc- is a standard way to exclude files from sdists; with backends like Hatch and Flit, VCS-tracked files and explicit include/exclude settings also affect what gets packaged.
If -bc-.claude/-bc- is visible to the backend’s file-selection logic, it can end up in an sdist, and in some configurations in other artifacts as well.
With setuptools, add:
If you use a -bc-pyproject.toml-bc- backend such as Hatch or Flit, prefer explicit include/exclude rules so -bc-.claude/-bc- is never selected in the first place.
Verify before publishing:
If you publish with Twine, remember Twine uploads artifacts; it does not audit them for sensitive files. The check has to happen before upload.
RubyGems
A gem’s contents come from -bc-spec.files-bc- in the -bc-.gemspec-bc-. Many gemspecs populate -bc-spec.files-bc- from git-tracked files, so anything tracked in git may be published unless you filter it out.
Add an explicit exclusion, for example:
Then you can build the gem and inspect the result by unpacking it:
Maven / Gradle (JVM)
The main compiled JAR usually does not include project-root dotfiles like -bc-.claude/-bc-. The bigger risk is custom source/resource configuration or published source JARs that sweep in more than intended. Maven Source Plugin builds source JARs from project sources, and Gradle’s -bc-withSourcesJar()-bc- publishes a JAR from the -bc-main-bc- source set.
Verify source artifacts explicitly:
General advice for any package manager
The pattern is the same everywhere: a build tool selects files and publishes an archive. The -bc-.claude/-bc- directory sits at your project root, just like -bc-.env-bc-. Treat it the same way.
Before publishing, inspect the exact archive contents and search for sensitive paths.
If your package manager supports a dry-run or preview mode, make it a standard step before every publish. The npm equivalent is -bc-npm pack --dry-run-bc-; other ecosystems often have an analogous way to inspect the artifact before release.
If The File Has Already Shipped
npm tarballs are permanent. Deprecating a version removes it from default install resolution but does not delete it and does not invalidate cached copies. Any credential that appeared in a published tarball should be considered compromised from the moment of publication, regardless of when it is discovered.
Rotate npm tokens at -bc-npmjs.com/settings/~/tokens-bc- and GitHub tokens at -bc-github.com/settings/tokens-bc-. For any other service whose credentials appeared in the file, rotate those too.
Conclusion
-bc-.claude/settings.local.json-bc- is not inherently dangerous, but it accumulates credentials as a side effect of normal use, and the current defaults do nothing to keep those credentials out of published packages. The fix is a single line in .npmignore. Add it before your next release.





