Back to Checks
aws

CodePipeline pipeline should use private repository source with authenticated connection

codepipeline_project_repo_private
Service: codepipelineSeverity: medium
OfficialBuilt-inVerified
Categories:software-supply-chainsecrets
Resource Type:AwsCodePipelinePipeline

CodePipeline pipeline should configure its source stage to use a private repository with authenticated connection rather than a public GitHub or GitLab repository. This ensures deployment configurations, build artifacts, and CI/CD logic remain protected from unauthorized access.

Risk

Using public repositories as pipeline sources exposes deployment configurations and CI/CD workflows to the internet, increasing risk of supply chain attacks, credential exposure, and intellectual property theft. Adversaries can inject malicious code or leverage exposed secrets to compromise production systems.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks codepipeline_project_repo_private

Recommendation

Configure CodePipeline source stages to use private repositories with AWS CodeStar Connections for GitHub or GitLab.

Apply least privilege to connection permissions, enable branch protection, require code review, use signed commits, and monitor pipeline execution logs. Consider AWS CodeCommit for fully managed private Git hosting with native IAM integration.

Remediation

CLI

aws codestar-connections create-connection --provider-type GitHub --connection-name my-github-connection
aws codepipeline update-pipeline --pipeline file://pipeline-config.json

Terraform

# Terraform: Configure pipeline with private repository via CodeStar Connection
resource "aws_codestarconnections_connection" "github" {
  name          = "my-github-connection"
  provider_type = "GitHub"  # or "GitLab"
}

resource "aws_codepipeline" "example" {
  name     = "my-pipeline"
  role_arn = aws_iam_role.codepipeline.arn

  stage {
    name = "Source"

    action {
      name             = "Source"
      category         = "Source"
      owner            = "AWS"
      provider         = "CodeStarSourceConnection"
      version          = "1"
      output_artifacts = ["source_output"]

      configuration = {
        ConnectionArn    = aws_codestarconnections_connection.github.arn
        FullRepositoryId = "myorg/myrepo"  # Private repository
        BranchName       = "main"
      }
    }
  }
}

NativeIaC

# CloudFormation: Configure pipeline with private repository via CodeStar Connection
Resources:
  MyConnection:
    Type: AWS::CodeStarConnections::Connection
    Properties:
      ConnectionName: my-github-connection
      ProviderType: GitHub  # or GitLab

  MyPipeline:
    Type: AWS::CodePipeline::Pipeline
    Properties:
      Stages:
        - Name: Source
          Actions:
            - Name: SourceAction
              ActionTypeId:
                Category: Source
                Owner: AWS
                Provider: CodeStarSourceConnection
                Version: 1
              Configuration:
                ConnectionArn: !GetAtt MyConnection.ConnectionArn
                FullRepositoryId: myorg/myrepo  # Private repository
                BranchName: main

Other

1In the AWS Console, navigate to **Developer Tools** → **Connections**
2Click **Create connection**
3Choose provider (GitHub or GitLab) and click **Connect**
4Authorize AWS to access your private repositories
5Navigate to **CodePipeline** → **Pipelines** and select your pipeline
6Click **Edit**
7In the **Source** stage, click **Edit action**
8Change **Action provider** to **GitHub (Version 2)** or **GitLab**
9Select **Connection** and choose the connection created in step 4
10Configure **Repository name** (private repo) and **Branch name**
11Click **Done** and **Save** the pipeline

Check Code

import ssl
import urllib.error
import urllib.request

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.codepipeline.codepipeline_client import (
    codepipeline_client,
)

HTTP_TIMEOUT = 30


class codepipeline_project_repo_private(Check):
    """Checks if AWS CodePipeline source repositories are configured as private.

    This check verifies whether source repositories (GitHub or GitLab) connected to
    CodePipeline are publicly accessible. It attempts to access the repositories
    anonymously to determine their visibility status.

    Attributes:
        None
    """

    def execute(self) -> list:
        """Executes the repository privacy check for all CodePipeline sources.

        Iterates through all CodePipeline pipelines and checks if their source
        repositories (GitHub/GitLab) are publicly accessible by attempting anonymous
        access.

        Returns:
            list: List of Check_Report_AWS objects containing the findings for each
                pipeline's source repository.
        """
        findings = []

        for pipeline in codepipeline_client.pipelines.values():
            if (
                pipeline.source
                and pipeline.source.type == "CodeStarSourceConnection"
                and pipeline.source.repository_id
            ):
                report = Check_Report_AWS(self.metadata(), resource=pipeline)
                report.region = pipeline.region
                report.resource_id = pipeline.name
                report.resource_arn = pipeline.arn
                report.resource_tags = pipeline.tags

                # Try both GitHub and GitLab URLs
                github_url = f"https://github.com/{pipeline.source.repository_id}"
                gitlab_url = f"https://gitlab.com/{pipeline.source.repository_id}"

                is_public_github = self._is_public_repo(github_url)
                is_public_gitlab = self._is_public_repo(gitlab_url)

                if is_public_github:
                    report.status = "FAIL"
                    report.status_extended = f"CodePipeline {pipeline.name} source repository is public: {github_url}"
                elif is_public_gitlab:
                    report.status = "FAIL"
                    report.status_extended = f"CodePipeline {pipeline.name} source repository is public: {gitlab_url}"
                else:
                    report.status = "PASS"
                    report.status_extended = f"CodePipeline {pipeline.name} source repository {pipeline.source.repository_id} is private."

                findings.append(report)

        return findings

    def _is_public_repo(self, repo_url: str) -> bool:
        """Checks if a repository is publicly accessible.

        Attempts to access the repository URL anonymously to determine if it's
        public or private.

        Args:
            repo_url: String containing the repository URL to check.

        Returns:
            bool: True if the repository is public, False if private or inaccessible.

        Note:
            The method considers a repository private if:
            - The URL redirects to a sign-in page
            - The request fails with HTTP errors
            - The URL is not accessible
        """
        if repo_url.endswith(".git"):
            repo_url = repo_url[:-4]

        try:
            req = urllib.request.Request(repo_url, method="HEAD")
            response = urllib.request.urlopen(req, timeout=HTTP_TIMEOUT)
            return not response.geturl().endswith("sign_in")
        except (urllib.error.URLError, TimeoutError, ssl.SSLError):
            return False