Conversation
… check
tokenAddressFormat ran ethers.isAddress() on any non-empty contractAddress
(and embedded tokenConfig.customToken.address). When the field holds a
runtime template reference such as `{{@prep:Prep.governor_address_safe}}`
-- which resolves to a real address at execution time -- the literal format
check failed and emitted a false invalid-token-address. governance-scanner
workflows that build their target address from a prior node flunked
validate_workflow despite executing fine.
Skip values containing a `{{...}}` template token before the isAddress
check, for both contractAddress and the embedded tokenConfig address.
Literal addresses are still validated; advisory-only (validateWorkflow is
not on the save/listing path).
KEEP-576
…sses
A contractAddress containing any {{...}} token is dynamic and cannot be
statically format-checked, so it is skipped even with a literal-looking
prefix. Locks the boundary two reviewers flagged.
…ution
collectContractRefs fed any non-empty contractAddress to resolveAbi during
the deep tier. A template reference like {{@prep:Prep.governor_address_safe}}
resolves to a real address only at execution time, so the literal template
always mismatched and emitted a spurious low-confidence-abi-match warning.
Skip refs whose contractAddress is a template token, reusing the
isTemplateReference helper now exported from validate-workflow-web3.
KEEP-576
Each Blockscout action now has an optional Chain selector that maps a chain ID to its hosted Blockscout instance, so a workflow can query Base, Optimism, Arbitrum, Gnosis, Polygon, the testnets, or Ethereum without configuring a connection. - Add BLOCKSCOUT_INSTANCES (chainId -> instance URL) and resolveInstance() in blockscout-core. Precedence: connection instance URL (self-hosted/rate-limit override) > selected chain's hosted instance > Ethereum mainnet default. - A selected chain with no known hosted instance and no connection now errors instead of silently falling back to Ethereum. - Thread an optional `network` (chain-select) input through all five actions; omitting it preserves the previous Ethereum-mainnet default, so existing workflows are unaffected. - Document supported chains and update unit tests (19 pass). Instance URLs verified live against each chain's Blockscout v2 API.
Move the chainId -> instance map to a client-safe chains.ts shared by the plugin definition and the step runtime. The Chain selector's allowedChainIds now derives from the same map instead of a hand-maintained list, so adding a chain is genuinely a one-line edit and the dropdown can't drift from the instances the runtime actually supports. (The map can't be imported from blockscout-core directly because that file is server-only and index.ts is client-loaded.)
fix(mcp): skip template-valued addresses in validate_workflow address check
…hain-select feat(blockscout): add chain selector for zero-config multi-chain queries
Extends safe-fetch buildBlockList with four IPv6 CIDRs (RFC 8215 site-local NAT64 64:ff9b:1::/48, Teredo 2001::/32, 6to4 2002::/16, documentation 2001:db8::/32) and adds a pre-DNS hostname denylist (isBlockedHost) covering localhost, *.local, *.internal, *.svc.cluster.local, *.pod.cluster.local. Both checks are wired into safeFetch and assertUrlIsPublic. Introduces assertConnectionUrlIsPublic as the single source of truth for non-HTTP outbound plugins. Wires it into the workflow database-query step (which previously called postgres.js with zero host validation) and into the existing test-connection endpoint. Tests cover all new CIDRs, the hostname denylist, the new SoT helper, and a regression assertion that the SoT never leaks the input connection string into error messages.
In shadow mode, a single request to a blocked target previously recorded two safe_fetch.blocks.total events: once from the entry-point check (pre-DNS hostname pattern, or IP-literal isBlockedIp), and again from the connector's post-DNS isBlockedIp after `localhost` -> 127.0.0.1 or for the IP literal itself. Inflated the exploit-attempt counter by 2x for those cases. Threads an `initialBlockRecorded` flag through pluginContext so the connector skips its own recordBlock when the synchronous check has already counted the request. Shadow-mode "log and continue" semantics preserved - the connect still attempts and the connector still throws in enforce mode; only the duplicate counter increment is suppressed. Tightens the existing IP-literal shadow-mode test to assert exactly one block call. Adds a regression test for the hostname-pattern shadow path (localhost).
…-guard hotfix: SSRF guard parity across HTTP and database plugins
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Promote the following merged PRs from staging to prod:
Post-deploy verification
deploy-keeperhubworkflow finishes greencurl -fsS https://app.keeperhub.com/api/healthreturns 200validate_workflowno longer rejects template-valued address fields (fix(mcp): skip template-valued addresses in validate_workflow address check #1325)