Skip to content

Sigp audit fixes#438

Open
JasonVranek wants to merge 47 commits intomainfrom
sigp-audit-fixes
Open

Sigp audit fixes#438
JasonVranek wants to merge 47 commits intomainfrom
sigp-audit-fixes

Conversation

@JasonVranek
Copy link
Copy Markdown
Collaborator

@JasonVranek JasonVranek commented Mar 19, 2026

Implements the recommended changes to address issues from the Sigma Prime audit report.

ManuelBilbao and others added 30 commits July 27, 2025 22:13
Co-authored-by: eltitanb <lorenzo@gattaca.com>
Co-authored-by: ltitanb <163874448+ltitanb@users.noreply.github.com>
Co-authored-by: Manuel Iñaki Bilbao <manuel.bilbao@lambdaclass.com>
Co-authored-by: eltitanb <lorenzo@gattaca.com>
Co-authored-by: ltitanb <163874448+ltitanb@users.noreply.github.com>
Co-authored-by: Manuel Iñaki Bilbao <manuel.bilbao@lambdaclass.com>
Co-authored-by: eltitanb <lorenzo@gattaca.com>
Co-authored-by: ltitanb <163874448+ltitanb@users.noreply.github.com>
Co-authored-by: Manuel Iñaki Bilbao <manuel.bilbao@lambdaclass.com>
Co-authored-by: ltitanb <163874448+ltitanb@users.noreply.github.com>
Co-authored-by: eltitanb <lorenzo@gattaca.com>
Co-authored-by: ltitanb <163874448+ltitanb@users.noreply.github.com>
Co-authored-by: Manuel Iñaki Bilbao <manuel.bilbao@lambdaclass.com>
Co-authored-by: eltitanb <lorenzo@gattaca.com>
Co-authored-by: ltitanb <163874448+ltitanb@users.noreply.github.com>
Co-authored-by: Manuel Iñaki Bilbao <manuel.bilbao@lambdaclass.com>
Co-authored-by: ltitanb <163874448+ltitanb@users.noreply.github.com>
Co-authored-by: Manuel Iñaki Bilbao <manuel.bilbao@lambdaclass.com>
Co-authored-by: Joe Clapis <jclapis@outlook.com>
@JasonVranek JasonVranek requested a review from a team March 20, 2026 21:57

fn make_local_signer_config(tls_mode: TlsMode) -> SignerConfig {
SignerConfig {
host: Ipv4Addr::new(127, 0, 0, 1),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can use Ipv4Addr::LOCALHOST

Comment on lines +476 to +480
let chain_id: U256;
match &*state.manager.read().await {
SigningManager::Local(local_manager) => {
chain_id = local_manager.get_chain().id();
if is_proxy {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would help readaility to refactor the match to return (chain_id, Result) which are later handled in the following map, rather than chaining these together directly

?req_id,
"Module signing ID not found"
);
return Err(SignerModuleError::RequestError("Module signing ID not found".to_string()));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we could return the request id too? otherwise there is no reason to construct it beforehand just to print it once

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same pattern was used in handle_request_signature_bls(). Don't think req_id provides any value since it's only generated server-side, and you can't easily correlate it back to a client-side request. I'm opting towards removing req_id from both bls/ecdsa signing paths and instead adding the pubkey + object_root + nonce to the error messages which are unambiguous and already public info.

Comment on lines +555 to +556
let chain_id: U256;
match &*state.manager.read().await {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

})
}

/// Helper to return if signer uses TLS
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'm not sure these comments are super helpful?

let jwts = load_jwt_secrets()?;
let (admin_secret, jwt_secrets) = load_jwt_secrets()?;

// Load the module signing configs
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

let mut seen_jwt_secrets = HashMap::new();
let mut seen_signing_ids = HashMap::new();
for module in modules {
// Validate the module ID
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: same as above. most other comments in this function are doing much either

pbs: StaticPbsConfig {
docker_image: String::from("cb-fake-repo/fake-cb:latest"),
pbs_config: PbsConfig {
host: Ipv4Addr::new(127, 0, 0, 1),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also LOCALHOST

Ok(claims)
}

/// Validate a JWT with the given secret
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: would remove?

Ok(())
}

/// Validate an admin JWT with the given secret
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: and this? given that it says the same thing as the function name

ltitanb
ltitanb previously approved these changes Mar 25, 2026
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add some tests here for singing and verifying signatures from a real world block? esp for the builder api messages

- add missing ADMIN_JWT_ENV and SIGNER_TLS_CERTIFICATES_PATH_ENV
- support https healthchecks
"Module {module_id} signing ID not found in commit-boost config, cannot reload"
);
error!(event = "reload", module_id = %module_id, error = %error_message);
return Err(SignerModuleError::RequestError(error_message));
Copy link
Copy Markdown
Contributor

@ninaiiad ninaiiad Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we're able to return midway through the loop it's strange that we're also updating the configs in place because we may exit and return an error to the client having half-updated the configs
It doesn't look like an actual vulnerability, but it's not clean and it's not obvious to the client I think

if you think it's better to be able to do this, then I think we should be able to communicate to the client which modules have been updated, also maybe save the error and continue updating other modules afterwards
though i would prefer to check first, update later only if all are ok

if elapsed > state.jwt_auth_fail_timeout {
drop(failures);
debug!("Removing {client_ip} from JWT auth failure list");
state.jwt_auth_failures.write().remove(client_ip);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a concurrency issue - we can't expect the state to have stayed the same after we've dropped the read lock above
there could've been another failure we missed in between the dropping of the read lock and the acquiring of the write lock where a new failure was added
not likely a big vulnerability either, but a bug nevertheless

SigningService::init_metrics(config.chain)?;

let app = axum::Router::new()
.route(REQUEST_SIGNATURE_PATH, post(handle_request_signature))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we keep the path as deprecated to avoid sudden breaking changes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants