CodeArtifact External Public Publishing Disabled
Overview
This check verifies that your internal AWS CodeArtifact packages are protected from accepting package versions from external public sources. When an internal package allows "upstream" ingestion, it can pull in versions from public repositories--which opens the door to a serious attack called dependency confusion.
Risk
If this check fails, your internal packages could be hijacked by malicious actors who publish higher-versioned packages to public repositories. When your build system requests a package, it may unknowingly download the attacker's version instead of your legitimate internal one.
Potential consequences:
- Malicious code running in your builds and applications
- Stolen secrets, credentials, or sensitive data
- Disrupted CI/CD pipelines and service outages
Severity: Critical
Remediation Steps
Prerequisites
- Access to the AWS Console with permissions to modify CodeArtifact packages, or
- AWS CLI installed and configured with appropriate credentials
Required IAM permissions
Your IAM user or role needs the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"codeartifact:PutPackageOriginConfiguration",
"codeartifact:DescribePackage",
"codeartifact:ListPackages"
],
"Resource": "*"
}
]
}
For production, scope the Resource to specific domains and repositories.
AWS Console Method
- Open the AWS CodeArtifact console
- In the left navigation, click Repositories
- Select the repository containing the flagged package
- Click on the package name that was identified in the Prowler finding
- Click the Origin controls tab
- Click Edit
- Set Upstream to Block
- Leave Publish set to Allow (unless you want to block direct publishing too)
- Click Save
Repeat for each package flagged by Prowler.
AWS CLI method
Use the put-package-origin-configuration command to block upstream ingestion:
aws codeartifact put-package-origin-configuration \
--domain <your-domain-name> \
--repository <your-repository-name> \
--format <package-format> \
--package <package-name> \
--restrictions publish=ALLOW,upstream=BLOCK \
--region us-east-1
Parameters:
--domain: Your CodeArtifact domain name--repository: The repository containing the package--format: Package type (one of:npm,pypi,maven,nuget,generic,ruby,swift,cargo)--package: The name of the package to protect--restrictions: Setupstream=BLOCKto prevent external ingestion
Example for an npm package:
aws codeartifact put-package-origin-configuration \
--domain my-company-domain \
--repository internal-packages \
--format npm \
--package my-internal-lib \
--restrictions publish=ALLOW,upstream=BLOCK \
--region us-east-1
For packages with namespaces (like scoped npm packages or Maven group IDs):
aws codeartifact put-package-origin-configuration \
--domain my-company-domain \
--repository internal-packages \
--format npm \
--namespace "@mycompany" \
--package core-utils \
--restrictions publish=ALLOW,upstream=BLOCK \
--region us-east-1
Bulk remediation script:
To fix all internal packages in a repository at once:
#!/bin/bash
DOMAIN="my-company-domain"
REPO="internal-packages"
FORMAT="npm"
REGION="us-east-1"
# List all packages and update each one
aws codeartifact list-packages \
--domain "$DOMAIN" \
--repository "$REPO" \
--format "$FORMAT" \
--region "$REGION" \
--query 'packages[*].package' \
--output text | while read PACKAGE; do
echo "Updating package: $PACKAGE"
aws codeartifact put-package-origin-configuration \
--domain "$DOMAIN" \
--repository "$REPO" \
--format "$FORMAT" \
--package "$PACKAGE" \
--restrictions publish=ALLOW,upstream=BLOCK \
--region "$REGION"
done
CloudFormation
AWS CloudFormation does not currently support AWS::CodeArtifact::PackageOriginConfiguration as a native resource type. You have two options:
Option 1: Use a Custom Resource with Lambda
AWSTemplateFormatVersion: '2010-09-09'
Description: CodeArtifact package origin configuration via custom resource
Parameters:
DomainName:
Type: String
Description: CodeArtifact domain name
RepositoryName:
Type: String
Description: CodeArtifact repository name
PackageFormat:
Type: String
AllowedValues:
- npm
- pypi
- maven
- nuget
- generic
- ruby
- swift
- cargo
PackageName:
Type: String
Description: Name of the package to configure
Resources:
PackageOriginConfigLambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: CodeArtifactAccess
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- codeartifact:PutPackageOriginConfiguration
Resource: '*'
PackageOriginConfigLambda:
Type: AWS::Lambda::Function
Properties:
Runtime: python3.11
Handler: index.handler
Role: !GetAtt PackageOriginConfigLambdaRole.Arn
Timeout: 30
Code:
ZipFile: |
import boto3
import cfnresponse
def handler(event, context):
try:
if event['RequestType'] in ['Create', 'Update']:
client = boto3.client('codeartifact')
client.put_package_origin_configuration(
domain=event['ResourceProperties']['Domain'],
repository=event['ResourceProperties']['Repository'],
format=event['ResourceProperties']['Format'],
package=event['ResourceProperties']['Package'],
restrictions={
'publish': 'ALLOW',
'upstream': 'BLOCK'
}
)
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
except Exception as e:
cfnresponse.send(event, context, cfnresponse.FAILED, {'Error': str(e)})
PackageOriginConfig:
Type: Custom::PackageOriginConfiguration
Properties:
ServiceToken: !GetAtt PackageOriginConfigLambda.Arn
Domain: !Ref DomainName
Repository: !Ref RepositoryName
Format: !Ref PackageFormat
Package: !Ref PackageName
Option 2: Post-deployment script
Deploy your CodeArtifact resources with CloudFormation, then run the AWS CLI command as a post-deployment step in your CI/CD pipeline.
Terraform
Terraform does not have a native resource for CodeArtifact package origin configuration. Use the null_resource with a local-exec provisioner or the AWS CLI.
Using null_resource:
variable "domain_name" {
description = "CodeArtifact domain name"
type = string
}
variable "repository_name" {
description = "CodeArtifact repository name"
type = string
}
variable "package_format" {
description = "Package format (npm, pypi, maven, etc.)"
type = string
}
variable "package_name" {
description = "Name of the package to configure"
type = string
}
resource "null_resource" "package_origin_config" {
triggers = {
domain = var.domain_name
repository = var.repository_name
format = var.package_format
package = var.package_name
}
provisioner "local-exec" {
command = <<-EOT
aws codeartifact put-package-origin-configuration \
--domain ${var.domain_name} \
--repository ${var.repository_name} \
--format ${var.package_format} \
--package ${var.package_name} \
--restrictions publish=ALLOW,upstream=BLOCK \
--region us-east-1
EOT
}
}
Using a module for multiple packages:
variable "packages_to_protect" {
description = "List of packages to configure origin controls"
type = list(object({
domain = string
repository = string
format = string
package = string
namespace = optional(string)
}))
}
resource "null_resource" "package_origin_configs" {
for_each = { for idx, pkg in var.packages_to_protect : "${pkg.domain}-${pkg.repository}-${pkg.package}" => pkg }
triggers = {
domain = each.value.domain
repository = each.value.repository
format = each.value.format
package = each.value.package
namespace = each.value.namespace
}
provisioner "local-exec" {
command = <<-EOT
aws codeartifact put-package-origin-configuration \
--domain ${each.value.domain} \
--repository ${each.value.repository} \
--format ${each.value.format} \
--package ${each.value.package} \
${each.value.namespace != null ? "--namespace ${each.value.namespace}" : ""} \
--restrictions publish=ALLOW,upstream=BLOCK \
--region us-east-1
EOT
}
}
Verification
After making changes, verify the configuration is correct:
- In the AWS Console, navigate to the package and confirm Upstream shows Block in the Origin controls tab
- Re-run the Prowler check to confirm remediation:
prowler aws --check codeartifact_packages_external_public_publishing_disabled -r us-east-1
CLI verification
Use the describe-package command to verify the origin configuration:
aws codeartifact describe-package \
--domain <your-domain-name> \
--repository <your-repository-name> \
--format <package-format> \
--package <package-name> \
--region us-east-1 \
--query 'package.originConfiguration.restrictions'
Expected output:
{
"publish": "ALLOW",
"upstream": "BLOCK"
}
Additional Resources
- AWS CodeArtifact Package Origin Controls
- Dependency Confusion Attack Explained
- AWS CodeArtifact User Guide
- put-package-origin-configuration CLI Reference
Notes
-
Preemptive protection: You can call
put-package-origin-configurationon package names that do not yet exist in your repository. This creates a placeholder that blocks upstream ingestion before the first version is even published. -
Package groups: For large-scale protection, consider using CodeArtifact package groups to apply origin controls to multiple packages matching a pattern.
-
Private namespaces: Use unique namespaces (like
@yourcompany/for npm) for internal packages to reduce the risk of name collisions with public packages. -
No service disruption: Changing origin controls does not affect existing package versions already in your repository. It only controls where new versions can come from.