A Jenkins Pipeline build fails with "Scripts not permitted to use method ...". What produced that message, and what are the ways to resolve it?
answer
- the controller holds every credential
- a Jenkinsfile is untrusted input
- every call is intercepted and checked
- the approval is not scoped to one job
- first fix: stop needing the API
basics
~20 sThe Groovy sandbox produced it. Jenkins runs pipeline scripts with every method call intercepted and checked against an approved list, and rejected the exact signature named in the message. Resolve it by rewriting to approved APIs or by having an administrator approve that signature.
solid answer
~50 sJenkinsfiles run inside the Groovy sandbox provided by the script-security plugin. Every method call, constructor and property access the script makes is intercepted and matched against a list of approved signatures; anything not on it throws a rejected-access error, which Jenkins renders as "Scripts not permitted to use method" followed by the exact signature. There are three responses. Rewrite the code to use a pipeline step or an already-approved API — usually the right one, since a step exists for most things people reach into Java for. Have an administrator approve the signature in Manage Jenkins under In-process Script Approval, remembering that approval is controller-wide and permanent: approving a reflection or file-access signature effectively hands controller-level power to anyone who can edit a Jenkinsfile. Or move the logic into a trusted global shared library, which runs outside the sandbox. Note that a Jenkinsfile loaded from source control always runs sandboxed; there is no per-job checkbox to turn that off.
code
groovy · 10 lines// Rejected by the sandbox: raw Java file access, and it would read
// the controller's filesystem rather than the agent's workspace.
// def text = new File('build.gradle').text
// Approved and agent-correct: use the pipeline step instead.
node {
checkout scm
def text = readFile 'build.gradle'
echo text.readLines().first()
}go deeper
Recognise the message as a permission refusal from the Groovy sandbox rather than a code bug, and know that an administrator, not you, decides whether a signature is allowed.
Explain the mechanism — calls intercepted and checked against approved signatures at runtime — and give the first fix: use a pipeline step or an already-approved API instead of raw Java.
Frame it as a threat model: the Jenkinsfile is untrusted input on the most privileged host, approval is a controller-wide permanent grant, and some signatures are a full escape from the boundary.
Own the policy: who may approve signatures, whether unrestricted logic belongs in a trusted shared library instead, and how the approval list gets audited rather than growing forever.
## What the sandbox is A Jenkinsfile is code that runs on the Jenkins controller — the process that holds every credential, every job configuration and the keys to every agent. Anyone who can open a pull request against a repository can propose a change to its Jenkinsfile. Without a restriction, "edit a file in a repo" would be equivalent to "run arbitrary code as the Jenkins service account". The **Groovy sandbox**, supplied by the script-security plugin, is that restriction. Pipeline scripts are compiled so that every method call, constructor invocation, field access and property access is intercepted at runtime and checked against a list of approved signatures. Approved ones proceed; anything else is refused. ## The error The refusal surfaces as a rejected-access error whose message names the precise signature the script tried to use, for example a `new java.io.File` constructor or a static method on some utility class. That specificity is deliberate: the message is meant to be actionable both for the developer and for the administrator who may be asked to approve it. Two notes that catch people out. First, the failure is at **runtime**, not parse time — the sandbox intercepts calls as they execute, so a rejected call in a rarely-taken branch can lie dormant for months. Second, it is unrelated to CPS serialization errors; the sandbox is about permission, the CPS transform is about durability, and they fail with different exceptions for different reasons. ## Resolving it **Rewrite to a step or an approved API.** This should be the first move. Pipelines have steps for most of what people reach into `java.io` or `java.nio` for: reading and writing workspace files, parsing structured files, archiving, stashing, HTTP calls through plugins. Steps also do the right thing with respect to agents — a step reads the file on the agent where the stage runs, whereas raw Java on a CPS-transformed line runs on the controller, which is almost never what the author intended. A sandbox rejection is often a hint that the code was going to work on the wrong machine anyway. **Approve the signature.** An administrator opens Manage Jenkins → In-process Script Approval, where every rejected signature is queued, and approves it. The consequences deserve care: - Approval is **controller-wide**. It is not scoped to the job, the folder or the branch that triggered it. Every sandboxed script on that controller may then use the signature. - Approval is **permanent** until someone revokes it, and the list is rarely audited. - Some signatures are effectively a full escape. Approving reflection, classloading, arbitrary process execution or `File` access means anyone able to edit any Jenkinsfile can read credentials from disk or run commands as the Jenkins user. So the correct posture is to treat the approval queue as a security review, not a chore. "Approve everything so builds stop failing" is the failure mode; it converts the sandbox into decoration. **Move the logic into a trusted shared library.** Code in a global shared library configured by an administrator runs outside the sandbox, on the reasoning that its source is controlled by people who already have controller-level trust. That relocates the decision rather than removing it: what mattered was who may change the code, and a trusted library answers that with repository permissions instead of an approval queue. ## Where the sandbox always applies A Jenkinsfile loaded from source control — a multibranch pipeline, or a job configured with "Pipeline script from SCM" — always runs in the sandbox. There is no checkbox to disable it there, and that is the point: SCM-provided scripts are exactly the untrusted input the sandbox exists to contain. ## The judgment being tested An interviewer asking this wants to see that you understand the threat model rather than the click path. The strong answer says: the Jenkinsfile is untrusted input running on the most privileged host in the delivery system; the sandbox is the boundary; the first fix is to stop needing the rejected API; approving a signature is a controller-wide, permanent grant that should be reviewed like any other privilege change; and if a team needs unrestricted code regularly, the answer is a trusted library owned by people who already hold that trust, not a longer approval list.
- What is the scope of approving a signature in In-process Script Approval?Controller-wide and permanent until revoked. It is not limited to the job, folder or branch that triggered the rejection, so every sandboxed script on that controller may then use it. That is why approving reflection, classloading or file-access signatures effectively grants controller-level power to anyone who can edit a Jenkinsfile.
- Why is a sandbox rejection often a sign the code was wrong anyway?Because raw Java in a pipeline script executes on the controller, not on the agent running the stage. Code that opens a file directly is usually trying to read the workspace, which lives on the agent. Switching to the equivalent step both passes the sandbox and reads the right machine's filesystem.
- How does a trusted shared library change the picture?Code in a global library configured by an administrator runs outside the sandbox, because its source is already controlled by trusted people. That moves the decision from an approval queue to repository permissions — which is usually the better place for it, but it is a relocation of trust, not a removal of it.
saying these in an interview costs you the question
- Approves every queued signature to unblock builds
- Thinks the sandbox error is a CPS serialization problem
- Believes approval applies only to the failing job
- Assumes SCM Jenkinsfiles can opt out of the sandbox
- Says the sandbox exists to catch typos rather than untrusted code