Skip to main content
Technical proposal SIMD-0163 Withdrawn

Lift the CPI caller restriction

  1. Idea
  2. Draft
  3. Review
  4. Accept
  5. Implement
  6. Active
  7. Withdrawn

Decision brief

Why this proposal matters

Remove the check which forces CPI callers to have the program account of the callee available to them as an instruction account.

Source-backed reading aid · source language: EN

Proposal at a glance

What changes

  • In CPI a feature gate must switch the search for the program id of the callee from the instruction accounts of the caller to the account list of the transaction.
  • Remove the check which forces CPI callers to have the program account of the callee available to them as an instruction account.

Stakeholder map

Who is affected

Builders & client teams Medium impact

Dapp developers who wish to benefit from the lifting of the restriction shall:

Action requirement unknown
Validators & operators Impact unknown

No proposal-specific evidence was found for this group.

Action requirement unknown
Users & stakers Medium impact

Transaction building should append the required program accounts, which are not passed as instruction accounts, at the end of the transaction accounts list. How the dapps describe which callee prorgams they require to be present in the transaction is explicitly left unspecified.

Action may be required
Governance & ecosystem Impact unknown

No proposal-specific evidence was found for this group.

Action requirement unknown

Exact source revision

Full proposal document

Source-language document. Technical identifiers and evidence remain unchanged. 0616093b2952

Summary

Remove the check which forces CPI callers to have the program account of the callee available to them as an instruction account.

Motivation

The restriction is purely historical and not necessary for the protocol or its implementations.

Removing it would improve composability and reduce transaction building complexity because program accounts would no longer be passed all the way from transaction level instructions to the inner most CPI instructions.

Additionally, not passing these program accounts is a significant reduction in data copied during serialization as program accounts of loader v1, v2 and v4 contain the entire 10 MB ELF. This massively reduces the CU cost for nested CPI and disincentivizes programs from accessing program accounts, which could later allow us to remove program loading from transaction loading.

Example transaction

  • Accounts:
    • Fee payer
    • Caller Program
    • Callee Program
    • Token
  • Transaction-level instruction:
    • Program Account: Caller Program
    • Instruction Accounts:
      • Callee Program (this could be removed)
      • Token
    • CPI:
      • Program Account: Callee Program
      • Instruction Accounts:
        • Token

Currently, in order to be used as a program account for a nested instruction the callee program must be passed as an instruction account to all outer instructions recursively.

New Terminology

None.

Detailed Design

In CPI a feature gate must switch the search for the program id of the callee from the instruction accounts of the caller to the account list of the transaction.

Invoking a program in CPI which was un/re/deployed in the same transaction is prevented by the "delay visibility" feature and thus unproblematic.

Alternatives Considered

None.

Impact

See motivation and security considerations.

Dapp developers who wish to benefit from the lifting of the restriction shall:

  • Hard-code the callee address in the CPI call, in case they want a static dispatch
  • Use the instruction data, not instruction accounts, to receive the callee address as a parameter, in case they want a dynamic dispatch

Transaction building should append the required program accounts, which are not passed as instruction accounts, at the end of the transaction accounts list. How the dapps describe which callee prorgams they require to be present in the transaction is explicitly left unspecified.

Security Considerations

For a program to be allowed to modify an account it must be the owner and the instruction account must have been passed in with the is_writable flag set. Some programs take custody of an accounts ownership and allow control via a signer authority. In these cases the instruction account must have been passed in with the is_signer flag set additionally. Both these flags can only be set in the inner most nested CPI if all parent CPIs did also set them. However, they can not be controlled at per top-level-instruction. All of these instructions share the same flags throughout the transaction.

This means the CPI caller restriction has been used as a security feature to prevent a top-level-instruction from calling into a program which has custody of an account that another top-level-instruction required as a signer. Removing this restriction would require a lot more care to be taken in transaction builing to prevent the relaxation from being exploited.

Backwards Compatibility

Programs remain unaffected the way they are, unless they want to profit from this change. In that case they can do one of the following:

Existing programs, which have hard-coded the callee statically and only need it as any instruction account to satisfy the constraint imposed by the runtime, can be fed a placeholder like NativeLoader1111111111111111111111111111111, in order not to shift the indices of the other instruction accounts.

All other existing programs, which dynamically call whatever is passed in a specific instruction account will have to be updated and redeployed to benefit from the lifting of the restriction.

Evidence graph

Related proposals and rollout

One or more sources are unavailable.

Upstream review record

Upstream discussion & review

GitHub review is editorial context, not evidence of on-chain support, voting, or outcome.

PR #163 · merged SIMD-0163: Lift the CPI caller restriction 23 comments and reviews · Jan 19, 2026
@Lichtso

we could have a new message header value which defines how many of the trailing readonly accounts are invokable Good idea, however outside of this SIMD. This is only about CPI, it does not affect the message accounts.

GitHub ↗
@cavemanloverboy

I agree. New transaction format needs to be thought through in great detail alongside https://github.com/solana-foundation/solana-improvement-documents/pull/172. I will draft something up in the next few weeks.

GitHub ↗
@2501babe

should we specify that non-instruction non-payer accounts must be read-only and enforce this in sanitize? or specify that writable non-instruction non-payer accounts are demoted to read-only? it wouldnt really affect lock contention because the only reason to append a writable account is to be annoying, and they could be just as annoying by taking it as an instruction account, but it would mean we dont need to check if a non-instruction account was invoked to skip it during account saving

GitHub ↗
@Lichtso

I don't think this SIMD is that much related to account loading. It needs all accounts containing programs to be loaded in the program cache, that's it. And that happens anyway, independent of writeability and later account saving.

GitHub ↗
@joncinque

It looks like there's consensus here. If no one objects within the next week, I'll merge this on 25 November.

GitHub ↗
@Nicola-Osec

We think there is a risk that some programs rely on inspecting instructions to determine whether other instructions might make a CPI call to a particular program. For example, right now is it possible to use the instructions sysvar to inspect other Instructions executing in the same tx, and you can guarantee that an instruction doesn't make a CPI call to a program if that program is not listed on the Instruction. Lifting this restriction (i.e. allowing instructions to call into programs not listed as instruction accounts) would make such a check insufficient.

GitHub ↗
@febo

We think there is a risk that some programs rely on inspecting instructions to determine whether other instructions might make a CPI call to a particular program. For example, right now is it possible to use the instructions sysvar to inspect other Instructions executing in the same tx, and you can guarantee that an instruction doesn't make a CPI call to a program if that program is not listed on the Instruction. Lifting this restriction (i.e. allowing instructions to call into programs not listed as instruction accounts) would make such a check insufficient. Related to this, the changes proposed in this SIMD expands the behaviour of what instructions can access in unpredictable ways, since

GitHub ↗
@joncinque

I had thought that this feature only restricts at the level of top-level instruction, meaning that each program in a top-level instruction could CPI into other programs declared within the top-level instruction, but I was told this isn't the case. While I think it's OK to lift the CPI caller restriction at the level of each top-level instruction, if we lift it at the transaction level, there are some dangerous possibilities, as Febo mentioned. Currently, it's possible to see dangers by looking at top-level instructions. For example, if you see an instruction take in the system program and your wallet as a signer, then you know that program could drain your wallet. With this change, however,

GitHub ↗

simd.watch community discussion · SIMD-0163

Powered by Giscus · Sign in with GitHub to comment

Community comments load when this section approaches the viewport.

Provenance

Evidence & technical details

Rollout or chain data, source revisions, freshness and integrity.
1

SIMD

Deployment Status

Document lifecycleWithdrawn
CategoryCore protocol
Devnetinactive
Testnetinactive
Mainnet-Betainactive
HcW8ZjBezYYgvcbxNJwqv1t484Y2556qJsfNDWvJGZRH

Exact source revision

Sources & integrity

  • Proposal document pinned_commit_blob
    0616093b2952ed6de52c4a27d66aadd11d48d4f9
  • simd-document document · current · Sep 11, 2026
    0616093b2952ed6de52c4a27d66aadd11d48d4f9

One or more sources are unavailable.