Join our Newsletter — 33% off our NHI Course
Home› Guides› Conda and Anaconda Supply Chain Guide: Channels, conda-forge,…
Guide Software & AI Supply Chain

Conda and Anaconda Supply Chain Guide: Channels, conda-forge, Lockfiles and Licence Exposure

PDF for newsletter subscribers · free to read online

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 14 November 2026 16 min read
On this page

Most organisations that run Python for data science pull binaries from conda channels without ever deciding which channels they trust, who builds those packages, or which licence terms apply to the download. Conda resolves packages from an ordered list of channels set across several configuration files, so one stray -c flag or a user's ~/.condarc can quietly change where code comes from. This guide covers channel trust and priority, how conda-forge builds and publishes, locking environments for reproducible and reviewable installs, administrator controls in .condarc, and the commercial exposure created by Anaconda's repository terms. It is written for platform engineers, AppSec teams and data platform owners. For the wider data science picture (notebooks, datasets, model files) see the Security for Data Science Teams; this page goes deeper on conda only.

This is an independent guide from NHI Mgmt Group, based on conda's public documentation, conda-forge's documentation and Anaconda's published terms as of November 2026. It is not sponsored or reviewed by Anaconda or the conda-forge project. Product features and terms change, so confirm settings against current documentation.

Key takeaways

  • Channels are your trust boundary. Every channel in the resolved list can supply code into the environment, so pick one primary source (defaults or conda-forge, as conda's own docs advise) and lock the list centrally.
  • Strict priority closes a substitution gap. The default channel_priority is flexible; strict stops a lower-priority channel from supplying a package name that a higher-priority channel already carries.
  • conda-forge is community-built. Its own 2025 incident notice says the packages "are built by strangers on the internet" and are not suitable where secure provenance is required, so treat it like any public index and add your own controls.
  • Lock and solve once. conda-lock produces per-platform lockfiles that install without a fresh solve, which turns dependency changes into reviewable diffs instead of runtime surprises.
  • Licence exposure is a supply chain risk too. Anaconda's terms require a paid Business Plan for for-profit organisations above 200 employees and contractors, and count CI/CD jobs as users, so unmanaged access to repo.anaconda.com is a compliance finding, not just a cost question.

How conda packages reach your machines

Conda installs prebuilt binary packages, often bundling compiled C, C++ and Fortran libraries, from channels. A channel is a URL that serves repository metadata (repodata) and package files. That differs from pip in two ways that matter for security: packages ship native code with no build step on your side, and one environment can draw from several channels at once. See the Python Packaging and pip Security Guide for the pip side, which still applies because most conda environments also contain pip-installed packages.

SourceWho builds and publishesDefault addressKey consideration
Anaconda defaultsAnaconda, Inc. on its build networkhttps://repo.anaconda.com/pkgs/Covered by Anaconda's terms of service, including the paid-plan threshold
conda-forgeCommunity maintainers, built on public CI from GitHub feedstocksconda.anaconda.org/conda-forge (via channel_alias)Anyone can contribute a package; review happens through pull requests
Other community channels (for example bioconda)Their own communitiesHosted on anaconda.org or elsewhereSeparate maintainers and build pipelines; mixing with conda-forge needs care over order
Personal or project channels on anaconda.orgAny account holderconda.anaconda.org/<user>No organisational review; the highest-risk source of ad hoc installs
Internal channel or repository proxyYour platform teamYour own URLOnly source you fully control; must respect upstream licence and mirroring terms

The channel_alias setting (default https://conda.anaconda.org) is the prefix conda adds to any bare channel name, so -c someuser resolves to an anaconda.org account. That is convenient for researchers and exactly why channel names typed from a blog post or README deserve the same suspicion as an unknown package name. The typosquatting and namespace patterns in the Malicious Package and Dependency Confusion Guide apply directly.

Channel priority and why it matters

Conda sorts candidate packages using channel order and the channel_priority setting. The configuration reference lists three values, strict, flexible (the default) and disabled.

SettingResolver behaviour (per conda docs)Supply chain effectWhen to use
strictPackages from lower-priority channels are excluded when a higher-priority channel has the same package nameA package name can only come from the first channel that carries it, which blocks name substitution from a later channelRecommended baseline; conda-forge also recommends it
flexiblePrefers higher-priority channels, sorting by channel priority, then version, then build number, but can fall backA later channel can still supply a package when the solver needs itLegacy environments that do not solve under strict
disabledNewest version from any listed channel winsAny channel in the list that publishes a higher version number wins, the dependency confusion patternAvoid in managed environments
  • One primary channel: conda's channel management page recommends configuring either defaults or conda-forge globally rather than both, because mixing builds can cause ABI incompatibility and "hard-to-debug runtime errors".
  • Per-package overrides: the channel::package syntax (for example conda-forge::numpy) pulls one package from a named channel and resolves its dependencies from the configured list. Allow it in reviewed environment files, not in ad hoc commands.
  • Override flag: --override-channels with --channel ignores the .condarc list for that command, so a locked list in configuration is only half the control; channel allowlisting (below) is the other half.
  • Base environment: conda-forge advises installing into a new environment rather than base. Keep base for conda itself so a bad package does not break the tool used to recover.

Inside conda-forge: what the build pipeline does and does not give you

Each conda-forge package lives in a feedstock, a GitHub repository that is "the home of one recipe", created after a recipe passes review in the staged-recipes repository. Linux and noarch packages build in Docker containers on CI; macOS and Windows use tuned CI runner images. Almost all changes arrive as pull requests, including automated version bumps from conda-forge-bot, and maintainers or the core team merge them.

Uploads go through two checks. Local validation on CI compares produced artefacts against the feedstock-outputs repository (which records which feedstock may publish which package name), and uploads happen only from qualifying events such as commits to main, not pull requests. Server-side validation then repeats the check before packages move from the cf-staging channel to conda-forge, to guard against interference at feedstock level.

That design is a real control against one feedstock publishing another project's package name, but it is not provenance in the sense your auditors mean. The project's April 2025 security notice (CVE-2025-31484) described misconfigured infrastructure, found during an external audit, that exposed the conda-forge channel's anaconda.org upload token to all feedstock maintainers from about 10 February to 1 April 2025. The token was disabled within the hour of notification, uploads were audited for staging bypasses and none were found, though the team noted that check "is not completely robust". The same notice states that conda-forge packages are not suitable for use cases that require secure software provenance. The customer-side lesson is the same as for the Ultralytics PyPI Compromise 2024: a publishing token in CI is a single point of failure, so your own pinning, scanning and mirroring decide what reaches production.

Integrity checks conda performs, and their limits

SettingDefaultWhat it doesRecommendation
ssl_verifytrueVerifies TLS certificates; also accepts a CA bundle path, a certificate directory or truststore for the OS storeNever set false; use truststore or a CA path behind TLS-inspecting proxies
safety_checkswarnEnforce available safety guarantees during package installationSet enabled on build agents and shared servers
extra_safety_checksfalseSpends extra time validating package contents, verifying SHA-256 for every file in each packageTurn on for production images and CI builds where install time is acceptable
signing_metadata_url_baseUnsetBase URL for trust metadata used by signature verificationSee the note on conda-content-trust below before relying on it
client_ssl_certUnsetClient certificate (and client_ssl_cert_key) for mutual TLS to a private channelPrefer this or short-lived tokens over long-lived static channel tokens

Anaconda designed conda signature verification on The Update Framework (TUF), with packages signed on its build network and root keys held offline. Its own page now states that, as of September 2026, conda-content-trust metadata signature verification is End of Support and "should not be relied on as a security control"; integrity rests on HTTPS, checksums in repository metadata and Anaconda's build and distribution controls. Plan on hash pinning and controlled channels as your integrity controls rather than client-side signatures.

Locking environments

An environment.yml with loose versions triggers a new solve every time it is installed, so two builds a week apart can contain different binaries. conda-lock runs the solve once per target platform and records the result, and installing from the lockfile does not invoke the solver.

  • Formats: the unified conda-lock.yml (multi-platform, the default), the explicit per-platform format that conda and mamba read natively (conda create --name ENV --file conda-linux-64.lock), and an environment-file rendering that re-solves on install and so gives up the locking benefit.
  • Pip inside conda: conda-lock integrates pip-solved packages, but only conda-lock itself can install those from the explicit format. Decide whether pip is allowed at all: add_pip_as_python_dependency defaults to true, so pip arrives with every Python.
  • Review: commit lockfiles, require review on changes, and regenerate on a schedule (for example monthly) rather than whenever someone hits a solve error. The trade-offs are covered in Dependency Pinning vs Version Ranges.
  • Inventory: a lockfile is also your software inventory for that environment; feed it to SBOM tooling. See the SBOM Guide.

Administrator controls in .condarc

Conda reads configuration from system locations (/etc/conda/, /var/lib/conda/ or C:/ProgramData/conda/), then $CONDA_ROOT, then user locations (~/.config/conda/, ~/.conda/, ~/.condarc), then the active environment, then $CONDARC. Later files supersede earlier ones, CONDA_* environment variables override all files, and command-line parameters win over everything. Lists and dictionaries merge; single values are replaced. That precedence means a central file only holds if you lock it.

  1. Restrict channels: set allowlist_channels to your approved list (the default empty list means no restriction). denylist_channels entries override allowlist entries, which helps block personal anaconda.org channels.
  2. Repoint defaults: use default_channels and custom_channels to send defaults and named channels to your internal repository, and set channel_alias so bare -c name requests also resolve internally.
  3. Lock with #!final: in the system .condarc of the installation, append #!final to a key so no other configuration source can overwrite it. The conda multi-user page shows channels and channel_alias locked this way, after which a search against an unlisted channel is refused as not in the allowed channels.
  4. Set integrity defaults: channel_priority: strict, safety_checks: enabled, extra_safety_checks: true in the same locked file.
  5. Remember the gaps: users who install their own Miniforge or Miniconda in their home directory bypass a system file entirely. Pair configuration with endpoint software control or an egress rule that only permits your internal repository host.

Licence exposure: Anaconda's repository terms

Anaconda's terms of service (page dated 15 July 2025) allow free use for individuals for personal, non-commercial purposes, for eligible academic and non-profit research organisations, and for for-profit organisations with 200 or fewer total employees or contractors, including all affiliates. Above that, a for-profit organisation must buy a Business Plan subscription. The terms state that they apply when Miniconda is used to access the platform, and Anaconda may request proof of eligibility.

  • Non-human users count: the terms FAQ defines users to include CI/CD jobs and other non-human clients, and counts as active any user that accessed artefacts from repo.anaconda.com or Anaconda-maintained repositories within the last 12 months. Build agents, container builds and notebook images are therefore in scope. Inventory them as non-human identities; see Human vs Non-Human Identity.
  • Mirroring: the terms prohibit framing or mirroring the platform, directly or via a proxy, unless authorised by Anaconda. Check your agreement before pointing a repository proxy at repo.anaconda.com.
  • conda-forge and the tool: the terms do not name conda-forge; they say third-party content is governed by its own licence, and refer anaconda.org use to separate terms. Many institutions have moved to Miniforge, which sets conda-forge as "the default (and only) channel". Moving channel is a supply chain change in its own right: rebuild and retest environments, because packages differ between channels.

Treat this as a joint task for procurement and engineering, not legal alone; the Open Source Licence Compliance Guide covers package-level licences, which still apply whichever channel you use.

Choosing a model

ModelSuitsControls you must add
Licensed Anaconda repository, defaults onlyOrganisations above the threshold wanting a vendor-built channel and supportLocked channel list, strict priority, licence inventory of human and CI users
conda-forge only via MiniforgeResearch groups and smaller teams needing breadth of packagesLockfiles, malware and vulnerability scanning, delayed adoption of new releases, no personal channels
Internal repository proxying approved upstreamsLarge or regulated organisationsUpstream terms review, quarantine period for new packages, single egress path, access tokens for the proxy managed as secrets
Curated internal channel built from sourceHigh-assurance and air-gapped environmentsOwn build pipeline, signing and provenance; highest effort, smallest package set

Small teams usually do best with one channel, lockfiles and the locked .condarc; the proxy and curated models pay off once several hundred users or regulated workloads are involved.

Where identity fits

Private channels and repository proxies are reached with tokens embedded in channel URLs, stored by anaconda login, or set in CI variables. Those tokens are non-human credentials: they end up in .condarc files committed to repositories, in Docker layers and in notebook outputs. Scope proxy tokens to read-only, rotate them, keep them out of images (pass them at build time as secrets), and scan repositories for them. Publishing tokens for internal channels need the tightest handling; see the PyPI API Tokens and Trusted Publishing Security Guide for the equivalent pattern and the Artifactory Tokens Security Guide if your proxy runs there.

How to implement

  1. Discover (weeks 1 to 2): find conda installations on endpoints, servers and images; collect every .condarc and environment.yml; list channels in use and every host that reaches repo.anaconda.com or conda.anaconda.org (proxy logs are the fastest source).
  2. Decide: choose a model from the table above and confirm the licence position for your headcount and CI users.
  3. Pilot (one team, two weeks): deploy the locked system .condarc with strict priority and an allowlist in audit-friendly form first (log refusals, keep a documented exception path), convert two key environments to conda-lock and build from lockfiles in CI.
  4. Roll out: push the configuration through your endpoint and image tooling, add the egress rule, and move CI to lockfile installs.
  5. Test: confirm a -c to an unlisted channel is refused, that --override-channels cannot reach a blocked host, and that lockfile installs are byte-identical across two builds.
  6. Roll back: keep the previous configuration and lockfiles versioned; removing the #!final keys restores prior behaviour, and a failed solve under strict can fall back to flexible for that environment only, recorded as an exception.

Detection and measurement

  • Egress logs: alert on requests to conda.anaconda.org paths outside your approved channel names and on any direct traffic to repo.anaconda.com when you route through a proxy.
  • Config drift: check images and hosts for ssl_verify: false, channel_priority: disabled and user-level channel lists.
  • Repository logs: new package names requested for the first time, and spikes in downloads from service accounts.
MetricTarget
Production environments built from a committed lockfile100%
Hosts and images with the locked system .condarcAbove 95%
Requests to unapproved channels per monthFalling to near zero after rollout
Median age of lockfiles in productionUnder 90 days
CI and human users of repo.anaconda.com mapped to a licence position100%

Framework mapping

Control areaNIST SP 800-53 Rev 5NIST CSF 2.0ISO/IEC 27001:2022 Annex ACIS Controls v8.1
Approved channels and allowlistingCM-7 Least Functionality, SR-3 Supply Chain Controls and ProcessesGV.SC-05A.8.19 Installation of software on operational systemsControl 2 Inventory and Control of Software Assets
Lockfiles and inventoryCM-8 System Component Inventory, SR-4 ProvenanceID.AM-02A.5.21 Managing information security in the ICT supply chainControl 2
Integrity checksSR-11 Component Authenticity, CM-14 Signed ComponentsPR.PS-02A.8.19Control 16 Application Software Security
Licence complianceSA-15 Development Process, Standards, and ToolsGV.SC-05A.5.32 Intellectual property rightsControl 2

The threat these controls address is MITRE ATT&CK T1195.001 Compromise Software Dependencies and Development Tools.

Common failure patterns

  • Mixed channels without strict priority: defaults and conda-forge both listed with flexible priority, giving unpredictable sourcing and ABI breakage.
  • Personal channels in production: a README's -c someuser copied into a Dockerfile, so an individual anaconda.org account becomes a production dependency.
  • Configuration that does not hold: a system .condarc without #!final, or users running their own installer, so the central policy is advisory only.
  • Disabling TLS checks: ssl_verify: false set to get past an inspecting proxy and then baked into a base image.
  • Licence surprise from CI: build agents and container builds pulling from repo.anaconda.com without anyone counting them as users.
  • Tokens in channel URLs: private channel tokens committed in .condarc or left in image layers, the same failure behind the PyPI Admin GitHub Token Leak 2024.

Practitioner checklist

  • Pick one primary channel and record the decision and its licence basis.
  • Set channel_priority: strict, safety_checks: enabled and extra_safety_checks: true centrally.
  • Enforce allowlist_channels and lock keys with #!final in the system .condarc.
  • Point channel_alias, default_channels and custom_channels at your internal repository if you run one.
  • Build every production environment from a committed conda-lock file.
  • Restrict egress to approved repository hosts so private installers cannot bypass policy.
  • Inventory CI jobs and humans that reach repo.anaconda.com against Anaconda's terms.
  • Treat channel and proxy tokens as secrets: read-only scope, rotation, scanning.
  • Subscribe to conda-forge and Anaconda security notices and rebuild when advisories land.

Standards and references

Related NHI Mgmt Group resources: Software Supply Chain Security Guide, Security for Data Science Teams, Python Packaging and pip Security Guide, Malicious Package and Dependency Confusion Guide.

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 14 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.