Skip to content

Commit

Permalink
MVP HardcodedContainerCredentials check
Browse files Browse the repository at this point in the history
  • Loading branch information
woodruffw committed Aug 28, 2024
1 parent 79deaa2 commit 2ba7455
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 0 deletions.
101 changes: 101 additions & 0 deletions src/audit/hardcoded_container_credentials.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use std::ops::Deref;

use github_actions_models::{
common::Expression,
workflow::{
job::{Container, DockerCredentials},
Job,
},
};

use crate::{
finding::{Confidence, Severity},
models::AuditConfig,
};

use super::WorkflowAudit;

pub(crate) struct HardcodedContainerCredentials<'a> {
pub(crate) _config: AuditConfig<'a>,
}

impl<'a> WorkflowAudit<'a> for HardcodedContainerCredentials<'a> {
fn ident() -> &'static str
where
Self: Sized,
{
"hardcoded-container-credentials"
}

fn new(config: crate::models::AuditConfig<'a>) -> anyhow::Result<Self>
where
Self: Sized,
{
Ok(Self { _config: config })
}

fn audit<'w>(
&self,
workflow: &'w crate::models::Workflow,
) -> anyhow::Result<Vec<crate::finding::Finding<'w>>> {
let mut findings = vec![];

for job in workflow.jobs() {
let Job::NormalJob(normal) = job.deref() else {
continue;
};

if let Some(Container::Container {
image: _,
credentials:
Some(DockerCredentials {
username: _,
password: Some(password),
}),
..
}) = &normal.container
{
// If the password doesn't parse as an expression, it's hardcoded.
if Expression::from_curly(password.into()).is_none() {
findings.push(
Self::finding()
.severity(Severity::High)
.confidence(Confidence::High)
.add_location(
job.location()
.annotated("container registry password is hard-coded"),
)
.build(workflow)?,
)
}
}

for (service, config) in normal.services.iter() {
if let Container::Container {
image: _,
credentials:
Some(DockerCredentials {
username: _,
password: Some(password),
}),
..
} = &config
{
if Expression::from_curly(password.into()).is_none() {
findings.push(
Self::finding()
.severity(Severity::High)
.confidence(Confidence::High)
.add_location(job.location().annotated(format!(
"service {service}: container registry password is hard-coded"
)))
.build(workflow)?,
)
}
}
}
}

Ok(findings)
}
}
1 change: 1 addition & 0 deletions src/audit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{
use anyhow::Result;

pub(crate) mod artipacked;
pub(crate) mod hardcoded_container_credentials;
pub(crate) mod impostor_commit;
pub(crate) mod pull_request_target;
pub(crate) mod ref_confusion;
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ fn main() -> Result<()> {
&audit::ref_confusion::RefConfusion::new(config)?,
&audit::use_trusted_publishing::UseTrustedPublishing::new(config)?,
&audit::template_injection::TemplateInjection::new(config)?,
&audit::hardcoded_container_credentials::HardcodedContainerCredentials::new(config)?,
];
for workflow in workflows.iter() {
// TODO: Proper abstraction for multiple audits here.
Expand Down

0 comments on commit 2ba7455

Please sign in to comment.