{"id":15045200,"url":"https://github.com/jenkinsci/script-security-plugin","last_synced_at":"2025-05-16T07:00:20.438Z","repository":{"id":14585080,"uuid":"17301604","full_name":"jenkinsci/script-security-plugin","owner":"jenkinsci","description":"Allows Jenkins admins to control what in-process scripts can be run by users","archived":false,"fork":false,"pushed_at":"2025-04-07T21:26:31.000Z","size":1735,"stargazers_count":69,"open_issues_count":11,"forks_count":166,"subscribers_count":108,"default_branch":"master","last_synced_at":"2025-04-08T16:07:45.274Z","etag":null,"topics":["groovy-scripts","jenkins-api-plugin","jenkins-plugin","script-approval","security"],"latest_commit_sha":null,"homepage":"https://plugins.jenkins.io/script-security","language":"Java","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jenkinsci.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-02-28T22:18:32.000Z","updated_at":"2025-04-04T04:18:36.000Z","dependencies_parsed_at":"2023-11-13T20:24:17.029Z","dependency_job_id":"6d6a5a81-3de2-4ef3-b66c-c046b480cfa2","html_url":"https://github.com/jenkinsci/script-security-plugin","commit_stats":{"total_commits":958,"total_committers":112,"mean_commits":8.553571428571429,"dds":0.6711899791231732,"last_synced_commit":"79b7281bc73d6db55cbaab3c5b1beef86cdeeaa0"},"previous_names":[],"tags_count":162,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jenkinsci%2Fscript-security-plugin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jenkinsci%2Fscript-security-plugin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jenkinsci%2Fscript-security-plugin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jenkinsci%2Fscript-security-plugin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jenkinsci","download_url":"https://codeload.github.com/jenkinsci/script-security-plugin/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254485025,"owners_count":22078764,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["groovy-scripts","jenkins-api-plugin","jenkins-plugin","script-approval","security"],"created_at":"2024-09-24T20:51:34.755Z","updated_at":"2025-05-16T07:00:20.189Z","avatar_url":"https://github.com/jenkinsci.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Script Security Plugin\n\n## User’s guide\n(adapted from information on [Template plugin in CloudBees Plugins guide](https://docs.cloudbees.com/docs/admin-resources/latest/plugins/template#template-sect-script-approval))\n\nVarious Jenkins plugins require that users define custom scripts, most commonly in the \nGroovy language, to customize Jenkins’s behavior. If everyone who writes these scripts is \na Jenkins administrator—specifically if they have the Overall/RunScripts permission, used \nfor example by the Script Console link—then they can write whatever scripts they like. \nThese scripts may directly refer to internal Jenkins objects using the same API offered to \nplugins. Such users must be completely trusted, as they can do anything to Jenkins (even \nchanging its security settings or running shell commands on the server).\n\nHowever, if some script authors are “regular users” with only more limited permissions, \nsuch as Job/Configure, it is inappropriate to let them run arbitrary scripts. To support \nsuch a division of roles, the Script Security library plugin can be integrated into \nvarious feature plugins. It supports two related systems: script approval, and Groovy \nsandboxing.\n\n### Script Approval\nThe first, and simpler, security system is to allow any kind of script to be run, but only \nwith an administrator’s approval. There is a globally maintained list of approved scripts \nwhich are judged to not perform any malicious actions.\n\nWhen a user saves some kind of configuration (for example, a job), there will be\nappropriate warnings indicating that approval is required. Administrators may approve those\nscripts using the Script Approval configuration page or following the approval link in the \nconfiguration.\nIn previous versions of Script Security Plugin, scripts saved by administrators where \nautomatically approved when saving them, but this functionality was disabled to prevent\na variety of social engineering-based attacks. (“Saving” usually means from the web UI, but\ncould also mean uploading a new XML configuration via REST or CLI.) or merely by creating a\nnew item copying an existing one.\n\nWhen a user saves a template configuration, a check is done whether any \ncontained scripts have been edited from an approved text. (More precisely, whether the \nrequested content has ever been approved before.) If it has not been approved, a request \nfor approval of this script is added to a queue. (A warning is also displayed in the \nconfiguration screen UI when the current text of a script is not currently approved.)\n\nAn administrator may now go to _Manage Jenkins » In-process Script Approval_ where a list \nof scripts pending approval will be shown. Assuming nothing dangerous-looking is being \nrequested, just click Approve to let the script be run henceforth.\n\nIf you try to run an unapproved script, it will simply fail, typically with a message \nexplaining that it is pending approval. You may retry once the script has been approved. \nThe details of this behavior may vary according to the feature plugin integrating this \nlibrary.\n\n### Groovy Sandboxing\nWaiting for an administrator to approve every change to a script, no matter how seemingly \ntrivial, could be unacceptable in a team spread across timezones or during tight \ndeadlines. As an alternative option, the Script Security system lets Groovy scripts be run \nwithout approval so long as they limit themselves to operations considered inherently \nsafe. This limited execution environment is called a sandbox. (Currently no sandbox \nimplementations are available for other languages, so all such scripts must be approved if \nconfigured by non-administrators.)\n\nTo switch to this mode, simply check the box Use Groovy Sandbox below the Groovy script’s \nentry field. Sandboxed scripts can be run immediately by anyone. (Even administrators, \nthough the script is subject to the same restrictions regardless of who wrote it.) When \nthe script is run, every method call, object construction, and field access is checked \nagainst a whitelist of approved operations. If an unapproved operation is attempted, the \nscript is killed and the corresponding Jenkins feature cannot be used yet.\n\nThe Script Security plugin ships with a small default whitelist, and integrating plugins \nmay add operations to that list (typically methods specific to that plugin).\n\nBut you are not limited to the default whitelist: every time a script fails before running \nan operation that is not yet whitelisted, that operation is automatically added to another \napproval queue. An administrator can go to the same page described above for approval of \nentire scripts, and see a list of pending operation approvals. If Approve is clicked next \nto the signature of an operation, it is immediately added to the whitelist and available \nfor sandboxed scripts.\n\nMost signatures be of the form `method class.Name methodName arg1Type arg2Type…`, \nindicating a Java method call with a specific “receiver” class (this), method name, and \nlist of argument (or parameter) types. (The most general signature of an attempted method \ncall will be offered for approval, even when the actual object it was to be called on was \nof a more specific type overriding that method.) You may also see `staticMethod` for \nstatic (class) methods, `new` for constructors, and `field` for field accesses (get or \nset).\n\nAdministrators in security-sensitive environments should carefully consider which \noperations to whitelist. Operations which change state of persisted objects (such as \nJenkins jobs) should generally be denied. Most `getSomething` methods are harmless.\n\nIn case of highly secured environments, where only sandbox scripts are allowed, the \noption \"Force the use of the sandbox globally in the system\" allows forcing the use of the \nsandbox globally in the system and will block the creation of new items in the \n\"In-process Script Approval\" screen.\n\n### ACL-aware methods\nBe aware however that even some “getter” methods are designed to check specific \npermissions (using an ACL: access control list), whereas scripts are often run by a system \npseudo-user to whom all permissions are granted. So for example` method \nhudson.model.AbstractItem getParent` (which obtains the folder or Jenkins root containing \na job) is in and of itself harmless, but the possible follow-up call `method \nhudson.model.ItemGroup getItems` (which lists jobs by name within a folder) checks \nJob/Read. This second call would be dangerous to whitelist unconditionally, since it would \nmean that a user who is granted Job/Create in a folder would be able to read at least some \ninformation from any jobs in that folder, even those which are supposed to be hidden \naccording to a project-based authorization strategy; it would suffice to create a job in \nthe folder which includes a Groovy script like this (details would vary according to the \nintegrating plugin):\n\n``` println(\"I sniffed ${thisjob.getParent().getItems()}!\"); ```\n\nWhen run, the script output would display at least the names of supposedly secret \nprojects. An administrator may instead click Approve assuming permission check for \n`getItems`; this will permit the call when run as an actual user (if the integrating \nplugin ever does so), while forbidding it when run as the system user (which is more \ntypical). In this case, `getItems` is actually implemented to return only those jobs which \nthe current user has access to, so if run in the former case (as a specific user), the \ndescription will show just those jobs they could see anyway. This more advanced button is \nshown only for method calls (and constructors), and should be used only where you know \nthat Jenkins is doing a permission check.\n\n## Developer’s guide\n[Complete example \nintegration](https://github.com/jenkinsci/groovy-postbuild-plugin/pull/11/files)\n\n### The easy way\nFor a typical Groovy integration, in which you offer the user the option of using either \nscript approval or the sandbox, change your describable’s String-valued script field into \na SecureGroovyScript field. In your constructor, before storing the value, call \n`configuringWithKeyItem` (if there could only be one such script per top-level item) or \nconfiguringWithNonKeyItem (if there might be several). The configuration form should use \n`\u003cf:property field=\"…\"/\u003e` to pick up the script and sandbox configuration. When you want \nto run the script, just call evaluate.\n\n(For compatibility with old data, pick a different field name and deprecate the original. \nThen you can define a readResolve method which sets the new field to a SecureGroovyScript \nwith the sandbox off, calls `configuring(ApprovalContext.create())` on it to notify the \nsystem that an unapproved script has been loaded, and unsets the old field.)\n\n### The hard way\nTo be used if you need more control than SecureGroovyScript offers:\n\nIntroduce a boolean sandbox field into your configuration.\n\nWhen unset, you need to call` ScriptApproval.configuring` in the `@DataBoundConstructor`. \nUse `ApprovalContext.withCurrentUser`, and also `withItemAsKey` where applicable (when \nthere is just one script per job); otherwise at least withItem where applicable, and/or \n`withKey` when you can uniquely identify this usage from the context \n(`StaplerRequest2.findAncestorObject` is helpful here). This lets the system know a \n(possibly) new script has been configured by a particular person. You will also need a \n`readResolve` that calls configuring to notify the system when a configurable with script \nhas been loaded from disk (and thus the configurer is unknown). Call \n`ScriptApproval.using` when the script is run, and catch `UnapprovedUsageException` if \nnecessary. The descriptor should use form validation on the script field and call \n`ScriptApproval.checking` (generally your descriptor should already be doing at least a \nsyntax check on this field).\n\nWhen the sandbox field is set, you need merely set up the Groovy shell with \n`GroovySandbox.createSecureCompilerConfiguration` and then call `GroovySandbox.run`; be \nprepared to catch `RejectedAccessException` and call `ScriptApproval.accessRejected`.\n\n### Preapproved methods for the sandbox\nTo preapprove some particular method calls, simply annotate them with @Whitelisted if in \nyour plugin; otherwise you can register (with `@Extension`) a ProxyWhitelist delegating to \nStaticWhitelist.from and loading a text file listing whitelisted methods.\n\n### Classpath for evaluating scripts\nWhen constructing a GroovyShell to evaluate a script, or calling \n`ecureGroovyScript.evaluate`, you must pass a `ClassLoader` which represents the effective \nclasspath for the script. You could use the loader of Jenkins core, or your plugin, or \n`Jenkins.getInstance().getPluginManager().uberClassLoader`.\n\nWhatever you choose, do not allow an unprivileged user to add arbitrary classpath entries \nby making a `URLClassLoader`! This would make it trivial to bypass all security when using \nthe sandbox. (A user need merely make this or another job archive a JAR containing some \nclass with a static method marked `@Whitelisted` and doing whatever they like, then call \nthe method from their script.) No attack has yet been demonstrated when using whole-script \napproval—a `URLClassLoader` with normal parent-first delegation would not permit trivial \nmasking of innocent-looking APIs by compromised versions—but it is likely that some clever \nuse of `META-INF/services/org.codehaus.groovy.transform.ASTTransformation` or similar \ncould cause an otherwise safe script to behave in an unexpected and unauthorized manner. \n[JENKINS-22834](https://issues.jenkins-ci.org/browse/JENKINS-22834) suggests a safe \nstandard alternative.\n\n### Unit tests\nWhen writing tests for plug-ins that use the Script Security Plugin you may encounter some \nerrors in your tests.\n\nIf your tests call, direct or indirectly, the `ScriptApproval.get()` method, then your \nunit tests must use JenkinsRule so that `Jenkins.getInstance()` does not return null. It \nis likely that tests that were working now start to fail if you are not using the sandbox. \nIt occurs because they are being enqueued for approval. In case you need to execute \nscripts regardless of approvals, `ScriptApproval.get().preapprove(script, \nGroovyLanguage.get())` will ensure that all configured scripts are approved. Alternately, \nyou can have your tests run scripts using the sandbox. In this case you may need to \nwhitelist methods used by your tests -- either generally for real users, or using a \n`@TestExtension` to have a whitelist just for tests.\n\n\n## Version history\n\nFrom of version 1.77 see [GitHub Releases](https://github.com/jenkinsci/script-security-plugin/releases).\n[Archives](https://github.com/jenkinsci/script-security-plugin/blob/71755e3bd5cf0f04acfcb5afc27b5a29252fca7e/CHANGELOG.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjenkinsci%2Fscript-security-plugin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjenkinsci%2Fscript-security-plugin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjenkinsci%2Fscript-security-plugin/lists"}