What IIQSR-983 means for your IdentityIQ install

On September 28, 2026, SailPoint disclosed CVE-2026-12342, a flaw that lets an unauthenticated user run code on the IdentityIQ server. SailPoint rates it 9.6 out of 10, and on October 2, it published e-fix IIQSR-983 to fix it. If you run SailPoint IdentityIQ, you need that e-fix, and you need it ASAP.

However, somewhat unusually, it isn’t a drop-in. It changes how IIQ handles dynamic values in forms, and some of what it changes won’t throw an error when it breaks. This post covers both halves: why it’s urgent, and what has to change in your configuration before (or right after) you apply it.


TL;DR

If someone can reach your IIQ instance, they can run arbitrary code without logging in. Colleagues at other consulting firms have reported seeing exploits in the wild.

  1. Patch now if your IdentityIQ install is reachable from the internet, and in your next patch cycle at the latest if it isn’t. Either way, start the prep work below now. Treat it as an emergency.
  2. Convert scriptlet field values (script:, rule:) in forms, and every scriptlet string in application and role provisioning policies, to Script or RuleRef elements. The provisioning policies fail silently, so start there.
  3. Warn your help desk about the new generic error on form submits, especially password changes.
  4. Test a create and an update through every application with a provisioning policy.

Why this one is serious

The short version: anyone who can reach your IdentityIQ web application can probably run arbitrary code on it, without logging in.

SailPoint describes the cause as “improper input validation of submitted web service API content.” That’s deliberately light on detail, and I’m going to leave it that way here (plenty of installs aren’t patched yet).

Code running inside IdentityIQ has IIQ’s database credentials and the credentials for every connected system, usually including admin access to Active Directory, HR and the mainframe. IIQ’s encryption doesn’t help, since that code can decrypt anything IIQ can. An identity governance system is about as close to “keys to everything” as an enterprise has.

If your install is reachable from the internet (commonly for self-service password reset or registration), treat this as an emergency. If it’s internal only, patch it in your next patch cycle at the latest. “Internal” includes any compromised laptop on your network. Either way, start the prep work now. This isn’t SailPoint’s usual unzip-it-over-the-top e-fix, and the configuration changes below need to be ready before (or right alongside) the patch.

What’s affected

The affected versions include every supported 8.x release. SailPoint has published the fix as e-fix zips for:

  • 8.5p2
  • 8.5 and 8.5p1
  • 8.4p2 through 8.4p4
  • 8.4p1
  • 8.4
  • 8.3p5

There’s no e-fix for 9.0, so it appears 9.0 already includes the fix. No 8.3, 8.4 or 8.5 patch release includes it yet. A later one (8.5p3, for example) probably will, since that’s how SailPoint has handled past e-fixes, but until then, staying current on patches won’t get you this fix. You need the e-fix.

We have confirmed the vulnerability on 8.5, along with the e-fix’s configuration changes described below. We’d expect the 8.4 and 8.3 e-fixes to behave the same way, but test your own version before you trust that.

Also, this fix does not supersede earlier security fixes. If you skipped some of SailPoint’s previous e-fixes, you still need those too. Compass has a security vulnerabilities page that lists what each version requires.


How to apply the e-fix

The mechanics are the usual e-fix process:

  1. Extract the zip for your version into the root of each IdentityIQ webapp (every UI server and every task server).
  2. Import WEB-INF/config/identityiq-IIQSR-983.xml.
  3. Restart every application server.
  4. Log in as a System Administrator and confirm IIQSR-983 shows up under Product Information at /identityiq/debug/about.jsf.

If you build with the Services Standard Build, drop the zip into base/efix/<version><patch>/ (for example base/efix/8.5p1/) and the build applies it for you. Check the built WAR for WEB-INF/efixes/identityiq-*-IIQSR-983.txt before you deploy it. An SSB build that quietly skips the e-fix gives you a WAR that looks patched in your change ticket and isn’t.

Two caveats:

  • The import XML replaces the stock Identity Refresh and Identity Update forms. If you customized either one, the import overwrites your changes. Export them first and re-apply your changes afterwards.
  • No 8.x patch release includes this fix yet, so if you move to a different 8.x patch level, apply that level’s e-fix again. When you eventually upgrade to a release that does include the fix (9.0 appears to, and future 8.x patches probably will), the e-fix’s class files and its WEB-INF/efixes text files have to be removed. Otherwise you end up running old classes on top of the new release.

Configuration changes required

This is the unusual part that takes some effort. IIQ has long let a field carry a “dynamic” value. For example, value="script:identity.getName()" runs that BeanShell, value="rule:My Rule" runs that rule, and value="ref:launcher" looks up a variable. The fix stops IIQ from treating user-supplied values as code, and to do that it also stops evaluating some dynamic values that administrators have been writing into configuration for years.

Form fields with script: or rule: values

Any form field whose value is a scriptlet string no longer gets evaluated. SailPoint’s README calls out script:, and rule: values behave the same way.

<Field displayName="Account ID" value="script:identity.getName()"/>

has to become

<Field displayName="Account ID">
  <Script>
    <Source>return identity.getName();</Source>
  </Script>
</Field>

and value="rule:My Rule" becomes a RuleRef on the field. Left alone, the field displays the literal text (script:identity.getName()) instead of a value, and if the form posts that value back on submit, the submit fails with the generic error described below. If the old scriptlet referenced the field’s current value (a common “default it if it’s empty” trick), test that carefully after you convert it.

Provisioning policies may fail silently

Provisioning policies on applications and roles are Forms that use the same underlying field model. Before the fix, a provisioning policy field whose value is a scriptlet string (script:, rule: or ref:) gets evaluated like any other. After it, the literal text is what gets provisioned (and call: values almost certainly behave the same way). Fields that use a Script element or a RuleRef are unaffected.

Instead of an error, you can end up provisioning an account whose description is literally script:return identity.getAttribute("title");. Nothing fails. You just find it later in the target system (or an auditor does).

Convert these to Script or RuleRef elements the same way as other Forms, and then test a create and an update through every application that has a policy.

What users can type

User-submitted form data is now checked. IIQ rejects any value that starts with script:, rule:, ref: or call: (regardless of case, leading spaces or a leading !), and any value containing $( followed later by ). So Pa$(word)1 is rejected, while cost is $5 (approx) is fine.

Unfortunately, the user doesn’t get a helpful message, either. They see IIQ’s generic “serious error” message with an incident code, and the real reason (“Dynamic input is not allowed in user form data”) only shows up in sailpoint.log. Real users rarely type those prefixes, but think about free-text fields (justifications, descriptions) and especially password fields, where $( is a perfectly reasonable thing for someone to have in a password. If you have password-related forms, tell your help desk what this looks like before the first call comes in, and make sure whoever reads the logs knows which message to look for.

What still works

These are confirmed unaffected in our testing, so you don’t need to rewrite them:

  • ref: values on form fields (for example value="ref:launcher")
  • $(variable) substitution in form field values
  • scriptlets in field attributes such as hidden and readOnly, and in allowed values definitions
  • workflow scriptlets: step actions, transitions, Arg values and variable initializers

Finding what needs to change

Start with source control, if your configuration lives there. Search the XML for value="script:, value="rule:, value="ref: and value="call: on Field elements, including the ProvisioningForms (or older Templates) inside Application and Bundle objects.

Then check the database, because anything that was only ever edited through the UI won’t be in your repository. From the Debug page (or the console’s export command), export these object types and run the same search:

  • Form
  • Application
  • Bundle (roles)
  • Workflow (approval steps can carry inline forms)
  • Plugin (settings forms)

Those two steps collapse into one when your Services Standard Build repository is actually authoritative for production. If every change reaches production through the repo, and the pipeline snapshots live configuration back into it (so nothing edited in the UI drifts away from source control), the search above is the whole answer and you can trust it. If the repo is “mostly” current, it’s only a starting point, and you’re back to exporting from every environment and reconciling what you find. A pipeline also keeps the fix fixed: add the same search as a lint rule and a scriptlet field value can’t quietly come back in next quarter’s release, and an automated provisioning test per application catches the policy problem above before it reaches a target system. (Building exactly this kind of pipeline is a big part of our DevOps work. If you don’t have one yet, it’s a good project for after the fire is out.)

WorkItem and WorkItemArchive objects hold copies of the forms that rendered them. Fix the source Form, Application, Role or Workflow rather than those copies, unless an in-flight work item itself depends on a scriptlet.

Custom Java and BeanShell are worth a quick look too. Code that builds a Field or DynamicValue with a raw "script:..." string and hands it to IIQ to evaluate is subject to the same change. Code that builds Script or Rule objects explicitly is fine.

Should you check whether you were hit?

If your install was reachable from the internet between disclosure on September 28, 2026 and the day you patched, yes.

At a minimum:

  • review your web server and application server access logs for unauthenticated requests to IIQ’s REST endpoints that don’t match normal user activity
  • look for rules, workflows, task definitions, identities and capabilities that were created or modified when nobody on your team was working on them
  • check the IIQ host for processes, scheduled jobs or files owned by the application server’s account that don’t belong there
  • if anything looks wrong, rotate the credentials IIQ holds for connected systems

None of that is specific to this flaw (it’s just what code execution on an identity system implies), but it’s a lot easier to do now than after someone asks.

If you'd like a second set of eyes on your configuration (or help getting the e-fix and these checks into your build and pipeline), let us know.

Scroll to Top