IBM Support

Batch Workload Visibility and Elevated Authority Analysis

How To


Summary

Batch jobs on IBM i represent one of the most overlooked security surfaces in enterprise environments. Unlike interactive jobs — where a user signs on, performs work, and signs off — batch jobs run unattended, often under service account profiles with elevated authority, and may execute programs that adopt additional authority at runtime.

Steps

1. Executive Summary

Batch jobs on IBM i represent one of the most overlooked security surfaces in enterprise environments. Unlike interactive jobs — where a user signs on, performs work, and signs off — batch jobs run unattended, often under service account profiles with elevated authority, and may execute programs that adopt additional authority at runtime. This creates a compounding risk:

  • A batch job submitted by a low-privilege user can run under a high-privilege service account
  • A program within that job can adopt the authority of its owner — a profile with *ALLOBJ — for the duration of a call
  • All of this happens without a sign-on event, without an operator present, and without explicit audit configuration targeting the batch infrastructure

This document provides SQL-based tooling to enumerate active and queued batch workloads, cross-reference job attributes with user privilege data, identify jobs with elevated effective access, and surface authority adoption chains.


2. Background — Work Management and Security Posture

2.1 Why Batch Jobs Are a Security Blind Spot

CharacteristicInteractive JobBatch Job
InitiationUser sign-onSBMJOB, job scheduler, or prestart job
Audit triggerSign-on event (type T)Job start event (type JS) — only if *JOBBAS/*JOBDTA auditing active
Running userAlways the signed-on userMay differ from submitting user (USER parameter)
DurationBounded by interactive sessionCan run hours, days, or indefinitely
Program authorityUser's own authorityMay include adopted authority from program owners
VisibilityAlways in active job tableMay be in job queue (pre-execution) or active

The combination of long-running execution, deferred start, and potential authority adoption makes batch infrastructure the most common path for privilege escalation without a detectable authentication event.

2.2 Key Identity Fields: JOB_USER vs. AUTHORIZATION_NAME vs. Effective Profile

FieldSource ViewMeaning
JOB_USERQSYS2.ACTIVE_JOB_INFOUser profile under which the job was submitted — the submitting identity
AUTHORIZATION_NAMEQSYS2.ACTIVE_JOB_INFOUser profile the job is currently running under — may differ from JOB_USER
USER_NAMESYSTOOLS.AUDIT_JOURNAL_JSUser attributed in the audit journal entry — typically the submitting user
EFFECTIVE_USER_PROFILESYSTOOLS.AUDIT_JOURNAL_JSUser the job was actually running under at the time of the journal event

Security implication: When AUTHORIZATION_NAME <> JOB_USER, the job has changed identity after submission. This is the primary indicator of impersonation or profile switching in a running job. See the cross-reference queries in Section 4.

2.3 Authority Adoption — How Programs Elevate Access

ElementDescription
Program attributeUSER_PROFILE = *OWNER
EffectAdds program owner's authority to the call stack for the duration of the program call
Chain behaviorAdopted authority accumulates across nested program calls — each *OWNER program adds its owner's authority
Risk conditionOwner holds *ALLOBJ or other special authority — effective authority during execution may far exceed the running user's nominal profile
Audit gapAuthority adoption is not audited by default — no journal entry is written when adoption begins or ends

3. SQL Queries — Batch Workload Visibility

Known system profiles: All queries in this document exclude jobs submitted by or running as QSYS and QTCP. The following profiles are also known to run expected system batch work — review in context rather than treating as automatic findings: QSECOFR (security officer), QTMHHTTP (IBM HTTP Server), QWEBADMIN (web administration), QPGMR (IBM-licensed program tasks).

3.1 Active Batch Jobs by Subsystem

-- Active batch jobs grouped by subsystem
-- Use to understand which subsystems carry the majority of batch workload
-- and which subsystems are running jobs under privileged profiles
SELECT
    J.SUBSYSTEM,
    J.SUBSYSTEM_LIBRARY_NAME,
    COUNT(*)                                         AS JOB_COUNT,
    COUNT(DISTINCT J.JOB_USER)                       AS UNIQUE_USERS,
    COUNT(DISTINCT J.AUTHORIZATION_NAME)             AS UNIQUE_CURRENT_USERS,
    SUM(CASE WHEN J.JOB_USER <> J.AUTHORIZATION_NAME
             THEN 1 ELSE 0 END)                      AS IDENTITY_MISMATCHES,
    SUM(CASE WHEN J.JOB_STATUS = 'RUN'  THEN 1 ELSE 0 END) AS RUNNING,
    SUM(CASE WHEN J.JOB_STATUS = 'MSGW' THEN 1 ELSE 0 END) AS WAITING_ON_MSG
FROM TABLE(QSYS2.ACTIVE_JOB_INFO()) AS J
WHERE J.JOB_TYPE = 'BCH'
  AND J.JOB_USER          NOT IN ('QSYS', 'QTCP')   -- Exclude system-submitted jobs
  AND J.AUTHORIZATION_NAME NOT IN ('QSYS', 'QTCP')  -- Exclude system running-as profiles
GROUP BY J.SUBSYSTEM, J.SUBSYSTEM_LIBRARY_NAME
ORDER BY JOB_COUNT DESC;

Sample Report

SUBSYSTEMSUBSYSTEM_LIBRARY_NAMEJOB_COUNTUNIQUE_USERSUNIQUE_CURRENT_USERSIDENTITY_MISMATCHESRUNNINGWAITING_ON_MSG
QBATCHQSYS142182379844
QBATCH2QSYS31562310
APPSBSAPPSLIB14330140
QSYSWRKQSYS999090

🔎

Findings: QBATCH shows 7 jobs where the running user differs from the submitted user — these are candidates for the identity mismatch query in Section 4.2. Investigate any subsystem with a non-zero IDENTITY_MISMATCHES count.

3.2 Active Batch Jobs by Job Queue

-- Active and queued batch jobs grouped by job queue
-- Use to identify over-loaded queues and queues attached to high-privilege subsystems
SELECT
    JOB_QUEUE,
    JOB_QUEUE_LIBRARY,
    COUNT(*)                                         AS JOB_COUNT,
    SUM(CASE WHEN JOB_STATUS = 'ACTIVE' THEN 1 ELSE 0 END) AS ACTIVE,
    SUM(CASE WHEN JOB_STATUS = 'JOBQ'   THEN 1 ELSE 0 END) AS QUEUED,
    SUM(CASE WHEN JOB_STATUS = 'OUTQ'   THEN 1 ELSE 0 END) AS OUTPUT_WAIT,
    COUNT(DISTINCT JOB_USER)                         AS UNIQUE_SUBMITTED_USERS,
    MIN(JOB_ENTERED_SYSTEM_TIME)                     AS OLDEST_JOB_ENTERED,
    MAX(JOB_ENTERED_SYSTEM_TIME)                     AS NEWEST_JOB_ENTERED
FROM TABLE(QSYS2.ACTIVE_JOB_INFO()) AS J
WHERE JOB_TYPE = 'BCH'
GROUP BY JOB_QUEUE, JOB_QUEUE_LIBRARY
ORDER BY JOB_COUNT DESC;

3.3 Active Batch Jobs by Submitted User

-- All active batch jobs grouped by the user who submitted them (JOB_USER)
-- Identifies which users have the most batch workload in flight
SELECT
    J.JOB_USER,
    COUNT(*)                                         AS JOB_COUNT,
    COUNT(DISTINCT J.SUBSYSTEM)                      AS SUBSYSTEMS_USED,
    COUNT(DISTINCT J.JOB_QUEUE)                      AS JOB_QUEUES_USED,
    SUM(CASE WHEN J.JOB_USER <> J.AUTHORIZATION_NAME
             THEN 1 ELSE 0 END)                      AS JOBS_WITH_IDENTITY_SWITCH,
    MIN(J.JOB_ENTERED_SYSTEM_TIME)                   AS EARLIEST_SUBMISSION,
    MAX(J.JOB_ENTERED_SYSTEM_TIME)                   AS LATEST_SUBMISSION
FROM TABLE(QSYS2.ACTIVE_JOB_INFO()) AS J
WHERE J.JOB_TYPE = 'BCH'
  AND J.JOB_USER          NOT IN ('QSYS', 'QTCP')
  AND J.AUTHORIZATION_NAME NOT IN ('QSYS', 'QTCP')
GROUP BY J.JOB_USER
ORDER BY JOB_COUNT DESC;

3.4 Active Batch Jobs by Current (Running) User

-- Grouped by AUTHORIZATION_NAME — the effective security context, not the submitting identity
-- A high-privilege profile appearing here with many jobs warrants scrutiny
SELECT
    J.AUTHORIZATION_NAME                             AS RUNNING_AS,
    COUNT(*)                                         AS JOB_COUNT,
    COUNT(DISTINCT J.JOB_USER)                       AS UNIQUE_SUBMITTERS,
    COUNT(DISTINCT J.SUBSYSTEM)                      AS SUBSYSTEMS,
    SUM(CASE WHEN J.JOB_USER <> J.AUTHORIZATION_NAME
             THEN 1 ELSE 0 END)                      AS RUNNING_AS_DIFFERENT_USER,
    MIN(J.JOB_ENTERED_SYSTEM_TIME)                   AS OLDEST_IN_QUEUE
FROM TABLE(QSYS2.ACTIVE_JOB_INFO()) AS J
WHERE J.JOB_TYPE = 'BCH'
  AND J.JOB_USER          NOT IN ('QSYS', 'QTCP')
  AND J.AUTHORIZATION_NAME NOT IN ('QSYS', 'QTCP')
GROUP BY J.AUTHORIZATION_NAME
ORDER BY JOB_COUNT DESC;

When a high-privilege profile (e.g., one holding *ALLOBJ) appears in RUNNING_AS with many jobs from varied submitters, this indicates batch workloads are consolidating under that profile's authority. Cross-reference with Query 4.1.

3.5 Job Queue Depth and Backlog

-- Job queue depth by job queue — uses SYSTOOLS.JOB_QUEUE_ENTRIES
-- Queued jobs are not yet running but will acquire the running user's authority when they start
SELECT
    A.JOB_QUEUE_NAME,
    A.JOB_QUEUE_LIBRARY,
    COUNT(*)                                         AS TOTAL_QUEUED,
    MIN(A.JOB_QUEUE_TIME)                            AS OLDEST_QUEUED,
    TIMESTAMPDIFF(4,
        CHAR(CURRENT_TIMESTAMP - CAST(MIN(A.JOB_QUEUE_TIME) AS TIMESTAMP)))
                                                     AS OLDEST_WAIT_MINUTES,
    COUNT(DISTINCT A.JOB_USER)                       AS UNIQUE_USERS
FROM SYSTOOLS.JOB_QUEUE_ENTRIES AS A
WHERE A.JOB_TYPE = 'BCH'
GROUP BY A.JOB_QUEUE_NAME, A.JOB_QUEUE_LIBRARY
ORDER BY TOTAL_QUEUED DESC;

4. SQL Queries — Cross-Referencing Jobs with Privilege Data

4.1 Active Jobs Running Under Profiles with Special Authority

-- Primary high-risk intersection: elevated profile actively running batch work
SELECT
    J.JOB_NAME,
    J.JOB_USER                                       AS SUBMITTED_BY,
    J.AUTHORIZATION_NAME                             AS RUNNING_AS,
    J.SUBSYSTEM,
    J.JOB_QUEUE,
    J.JOB_STATUS,
    J.JOB_ENTERED_SYSTEM_TIME,
    U.USER_CLASS_NAME,
    U.SPECIAL_AUTHORITIES,
    U.STATUS                                         AS PROFILE_STATUS,
    CASE
        WHEN U.SPECIAL_AUTHORITIES LIKE '%*ALLOBJ%'  THEN 'CRITICAL'
        WHEN U.SPECIAL_AUTHORITIES LIKE '%*SECADM%'  THEN 'HIGH'
        WHEN U.SPECIAL_AUTHORITIES LIKE '%*JOBCTL%'
          OR U.SPECIAL_AUTHORITIES LIKE '%*IOSYSCFG%'
          OR U.SPECIAL_AUTHORITIES LIKE '%*AUDIT%'   THEN 'MEDIUM'
        ELSE 'LOW'
    END                                              AS RISK_LEVEL
FROM TABLE(QSYS2.ACTIVE_JOB_INFO()) AS J
JOIN QSYS2.USER_INFO AS U
    ON U.AUTHORIZATION_NAME = J.AUTHORIZATION_NAME
WHERE J.JOB_TYPE            = 'BCH'
  AND U.SPECIAL_AUTHORITIES <> '*NONE'
  AND J.JOB_USER          NOT IN ('QSYS', 'QTCP')
  AND J.AUTHORIZATION_NAME NOT IN ('QSYS', 'QTCP')
ORDER BY RISK_LEVEL, J.AUTHORIZATION_NAME, J.JOB_NAME;

Sample Report

JOB_NAMESUBMITTED_BYRUNNING_ASSUBSYSTEMJOB_STATUSSPECIAL_AUTHORITIESRISK_LEVEL
047821/APPSVC/NIGHTLY01APPSVCAPPSVCQBATCHACTIVE*ALLOBJ *SECADM *JOBCTLCRITICAL
047854/APPSVC/NIGHTLY02APPSVCAPPSVCQBATCHACTIVE*ALLOBJ *SECADM *JOBCTLCRITICAL
047901/JDOE/REPORT01JDOEBATCHSVCQBATCHACTIVE*JOBCTLMEDIUM
047912/BATCHSVC/SYNC01BATCHSVCBATCHSVCQBATCH2JOBQ*SAVSYS *JOBCTLMEDIUM

🔎

Findings: APPSVC holds *ALLOBJ with 2 active overnight batch jobs — highest risk. The JDOEBATCHSVC pattern (submitted by JDOE, running under BATCHSVC) warrants investigation via Query 4.2.

4.2 Jobs Where Running User Differs from Submitted User

-- Indicates SBMJOB USER(other), profile switching, or prestart job reuse
-- Join with USER_INFO to show the privilege level of both identities
SELECT
    J.JOB_NAME,
    J.JOB_USER                                       AS SUBMITTED_BY,
    US.SPECIAL_AUTHORITIES                           AS SUBMITTER_AUTHORITIES,
    J.AUTHORIZATION_NAME                             AS RUNNING_AS,
    UR.SPECIAL_AUTHORITIES                           AS RUNNING_AUTHORITIES,
    J.SUBSYSTEM,
    J.JOB_QUEUE,
    J.JOB_STATUS,
    J.JOB_ENTERED_SYSTEM_TIME,
    CASE
        WHEN UR.SPECIAL_AUTHORITIES LIKE '%*ALLOBJ%' THEN 'CRITICAL'
        WHEN UR.SPECIAL_AUTHORITIES LIKE '%*SECADM%' THEN 'HIGH'
        WHEN UR.SPECIAL_AUTHORITIES <> '*NONE'       THEN 'MEDIUM'
        ELSE 'INFO'
    END                                              AS RISK_ASSESSMENT
FROM TABLE(QSYS2.ACTIVE_JOB_INFO()) AS J
JOIN QSYS2.USER_INFO AS US
    ON US.AUTHORIZATION_NAME = J.JOB_USER
JOIN QSYS2.USER_INFO AS UR
    ON UR.AUTHORIZATION_NAME = J.AUTHORIZATION_NAME
WHERE J.JOB_TYPE    = 'BCH'
  AND J.JOB_USER   <> J.AUTHORIZATION_NAME
  AND J.JOB_USER          NOT IN ('QSYS', 'QTCP')
  AND J.AUTHORIZATION_NAME NOT IN ('QSYS', 'QTCP')
ORDER BY RISK_ASSESSMENT, J.JOB_NAME;

4.3 Batch Jobs Running Under Disabled Profiles

-- A disabled profile should not be the running identity for any active work
-- This indicates a profile was disabled while jobs were in flight
SELECT
    J.JOB_NAME,
    J.JOB_USER                                       AS SUBMITTED_BY,
    J.AUTHORIZATION_NAME                             AS RUNNING_AS,
    U.STATUS                                         AS PROFILE_STATUS,
    U.SPECIAL_AUTHORITIES,
    J.SUBSYSTEM,
    J.JOB_STATUS,
    J.JOB_ENTERED_SYSTEM_TIME
FROM TABLE(QSYS2.ACTIVE_JOB_INFO()) AS J
JOIN QSYS2.USER_INFO AS U
    ON U.AUTHORIZATION_NAME = J.AUTHORIZATION_NAME
WHERE J.JOB_TYPE = 'BCH'
  AND U.STATUS   = '*DISABLED'
  AND J.JOB_USER          NOT IN ('QSYS', 'QTCP')
  AND J.AUTHORIZATION_NAME NOT IN ('QSYS', 'QTCP')
ORDER BY J.JOB_ENTERED_SYSTEM_TIME;

IBM i does not forcibly end a running job when its user profile is disabled. Jobs already active continue to run. This query surfaces jobs operating as "ghost" identities — the profile is disabled but actively executing batch work.


5. SQL Queries — Adopted Authority and Elevated Effective Access

Important prerequisite: Authority adoption is a program-level attribute, not a job-level attribute. These queries identify programs configured to adopt authority and their owners' privilege levels. They do not confirm that a program is currently on the call stack — that level of visibility requires *JOBDTA auditing and call stack capture.

5.1 Programs with Adopted Authority (*OWNER)

Performance note: QSYS2.PROGRAM_INFO scans every *PGM object across all libraries on the system. On a system with a large number of libraries or program objects this query can take several minutes to complete. Consider running during off-peak hours or restricting PROGRAM_LIBRARY to specific application libraries if a full-system scan is not required.

-- All *PGM objects configured to adopt owner authority (USER_PROFILE = *OWNER)
-- Cross-referenced with the owner's special authority level
-- QSYS-owned IBM-supplied programs are excluded
SELECT
    P.PROGRAM_LIBRARY                                AS LIBRARY,
    P.PROGRAM_NAME,
    P.OBJECT_TYPE,
    P.PROGRAM_OWNER                                  AS OWNER,
    P.CREATE_TIMESTAMP                               AS CREATED,
    U.STATUS                                         AS OWNER_STATUS,
    U.SPECIAL_AUTHORITIES                            AS OWNER_AUTHORITIES,
    U.USER_CLASS_NAME                                AS OWNER_CLASS,
    CASE
        WHEN U.SPECIAL_AUTHORITIES LIKE '%*ALLOBJ%'  THEN 'CRITICAL'
        WHEN U.SPECIAL_AUTHORITIES LIKE '%*SECADM%'  THEN 'HIGH'
        WHEN U.SPECIAL_AUTHORITIES <> '*NONE'        THEN 'MEDIUM'
        WHEN U.STATUS = '*DISABLED'                  THEN 'REVIEW'
        ELSE 'LOW'
    END                                              AS RISK_LEVEL
FROM QSYS2.PROGRAM_INFO AS P
JOIN QSYS2.USER_INFO AS U
    ON U.AUTHORIZATION_NAME = P.PROGRAM_OWNER
WHERE P.USER_PROFILE  = '*OWNER'
  AND P.OBJECT_TYPE   = '*PGM'
  AND P.PROGRAM_OWNER <> 'QSYS'
ORDER BY RISK_LEVEL, P.PROGRAM_LIBRARY, P.PROGRAM_NAME;

Sample Report

LIBRARYPROGRAM_NAMEOBJECT_TYPEOWNERCREATEDOWNER_AUTHORITIESRISK_LEVEL
APPLIBPOSTCLOSE*PGMQSECOFR2019-03-14*ALLOBJ *SECADM *JOBCTLCRITICAL
APPLIBNITECLOSE*PGMAPPSVC2021-06-01*ALLOBJ *SECADMCRITICAL
RPTLIBRUNJRNRPT*PGMQSYSOPR2020-11-20*JOBCTL *SAVSYSMEDIUM
UTILLIBCLROUTQ*PGMQSECOFR2018-05-10*ALLOBJ *SECADM *JOBCTLCRITICAL

🔎

Findings: POSTCLOSE and NITECLOSE in APPLIB are owned by highly privileged profiles and adopt authority on every call. Any batch job calling these programs temporarily acquires *ALLOBJ for the duration of the call.

5.2 Jobs with Access to Adopted-Authority Programs

-- Active batch jobs whose running user has access to programs that adopt *ALLOBJ
-- Shows eligibility — not confirmation the program is currently on the call stack
SELECT
    J.JOB_NAME,
    J.JOB_USER                                       AS SUBMITTED_BY,
    J.AUTHORIZATION_NAME                             AS RUNNING_AS,
    J.SUBSYSTEM,
    J.JOB_STATUS,
    P.PROGRAM_LIBRARY                                AS ADOPTED_AUTH_PGM_LIBRARY,
    P.PROGRAM_NAME                                   AS ADOPTED_AUTH_PROGRAM,
    P.PROGRAM_OWNER,
    U.SPECIAL_AUTHORITIES                            AS OWNER_AUTHORITIES
FROM TABLE(QSYS2.ACTIVE_JOB_INFO()) AS J
JOIN QSYS2.PROGRAM_INFO AS P
    ON P.USER_PROFILE = '*OWNER'
   AND P.OBJECT_TYPE  = '*PGM'
JOIN QSYS2.USER_INFO AS U
    ON U.AUTHORIZATION_NAME = P.PROGRAM_OWNER
   AND U.SPECIAL_AUTHORITIES LIKE '%*ALLOBJ%'
WHERE J.JOB_TYPE = 'BCH'
  AND J.JOB_USER          NOT IN ('QSYS', 'QTCP')
  AND J.AUTHORIZATION_NAME NOT IN ('QSYS', 'QTCP')
  AND P.PROGRAM_OWNER     <> 'QSYS'
ORDER BY J.AUTHORIZATION_NAME, P.PROGRAM_LIBRARY, P.PROGRAM_NAME;

5.3 Programs Adopting Authority Owned by Privileged Profiles

-- Grouped by owner to show concentration of adopted-authority exposure
SELECT
    P.PROGRAM_OWNER,
    U.USER_CLASS_NAME,
    U.SPECIAL_AUTHORITIES,
    U.STATUS                                         AS OWNER_STATUS,
    COUNT(*)                                         AS ADOPTING_OBJECT_COUNT,
    SUM(CASE WHEN P.OBJECT_TYPE = '*PGM'    THEN 1 ELSE 0 END) AS PROGRAMS,
    SUM(CASE WHEN P.OBJECT_TYPE = '*SRVPGM' THEN 1 ELSE 0 END) AS SERVICE_PROGRAMS,
    LISTAGG(DISTINCT P.PROGRAM_LIBRARY, ', ')
        WITHIN GROUP (ORDER BY P.PROGRAM_LIBRARY)    AS LIBRARIES
FROM QSYS2.PROGRAM_INFO AS P
JOIN QSYS2.USER_INFO AS U
    ON U.AUTHORIZATION_NAME = P.PROGRAM_OWNER
WHERE P.USER_PROFILE = '*OWNER'
  AND P.OBJECT_TYPE  IN ('*PGM', '*SRVPGM')
  AND (U.SPECIAL_AUTHORITIES LIKE '%*ALLOBJ%'
    OR U.SPECIAL_AUTHORITIES LIKE '%*SECADM%')
GROUP BY P.PROGRAM_OWNER, U.USER_CLASS_NAME, U.SPECIAL_AUTHORITIES, U.STATUS
ORDER BY ADOPTING_OBJECT_COUNT DESC;

5.4 Service Programs in Authority Adoption Chains

-- *SRVPGM objects with USER_PROFILE(*OWNER)
-- Called via procedure interfaces — hardest to trace in call stacks; highest audit gap
SELECT
    P.PROGRAM_LIBRARY                                AS LIBRARY,
    P.PROGRAM_NAME                                   AS SERVICE_PROGRAM,
    P.PROGRAM_OWNER                                  AS OWNER,
    P.CREATE_TIMESTAMP                               AS CREATED,
    U.SPECIAL_AUTHORITIES                            AS OWNER_AUTHORITIES,
    U.STATUS                                         AS OWNER_STATUS,
    CASE
        WHEN U.SPECIAL_AUTHORITIES LIKE '%*ALLOBJ%'  THEN 'CRITICAL'
        WHEN U.SPECIAL_AUTHORITIES LIKE '%*SECADM%'  THEN 'HIGH'
        WHEN U.SPECIAL_AUTHORITIES <> '*NONE'        THEN 'MEDIUM'
        ELSE 'LOW'
    END                                              AS RISK_LEVEL
FROM QSYS2.PROGRAM_INFO AS P
JOIN QSYS2.USER_INFO AS U
    ON U.AUTHORIZATION_NAME = P.PROGRAM_OWNER
WHERE P.USER_PROFILE = '*OWNER'
  AND P.OBJECT_TYPE  = '*SRVPGM'
ORDER BY RISK_LEVEL, P.PROGRAM_LIBRARY, P.PROGRAM_NAME;

6. SQL Queries — Comprehensive Risk Dashboard

6.1 Full Batch Security Risk Summary

-- Combines job identity, privilege level, and identity-switch detection in a single view
-- Designed for daily or weekly security reporting on batch workload posture
SELECT
    J.JOB_NAME,
    J.JOB_USER                                       AS SUBMITTED_BY,
    J.AUTHORIZATION_NAME                             AS RUNNING_AS,
    J.SUBSYSTEM,
    J.JOB_QUEUE,
    J.JOB_STATUS,
    J.JOB_ENTERED_SYSTEM_TIME,
    U.USER_CLASS_NAME,
    U.SPECIAL_AUTHORITIES,
    U.STATUS                                         AS PROFILE_STATUS,
    CASE WHEN J.JOB_USER <> J.AUTHORIZATION_NAME
         THEN 'YES' ELSE 'NO' END                    AS IDENTITY_SWITCHED,
    CASE WHEN U.SPECIAL_AUTHORITIES LIKE '%*ALLOBJ%'  THEN 'CRITICAL'
         WHEN U.SPECIAL_AUTHORITIES LIKE '%*SECADM%'  THEN 'HIGH'
         WHEN U.SPECIAL_AUTHORITIES LIKE '%*AUDIT%'
           OR U.SPECIAL_AUTHORITIES LIKE '%*IOSYSCFG%'
           OR U.SPECIAL_AUTHORITIES LIKE '%*JOBCTL%'  THEN 'MEDIUM'
         WHEN J.JOB_USER <> J.AUTHORIZATION_NAME     THEN 'REVIEW'
         WHEN U.STATUS = '*DISABLED'                  THEN 'REVIEW'
         ELSE 'LOW'
    END                                              AS RISK_LEVEL
FROM TABLE(QSYS2.ACTIVE_JOB_INFO()) AS J
JOIN QSYS2.USER_INFO AS U
    ON U.AUTHORIZATION_NAME = J.AUTHORIZATION_NAME
WHERE J.JOB_TYPE = 'BCH'
  AND J.JOB_USER          NOT IN ('QSYS', 'QTCP')
  AND J.AUTHORIZATION_NAME NOT IN ('QSYS', 'QTCP')
ORDER BY RISK_LEVEL, J.AUTHORIZATION_NAME, J.JOB_NAME;

Sample Report

JOB_NAMESUBMITTED_BYRUNNING_ASSUBSYSTEMJOB_STATUSSPECIAL_AUTHORITIESIDENTITY_SWITCHEDRISK_LEVEL
048201/APPSVC/NIGHTLY01APPSVCAPPSVCQBATCHRUN*ALLOBJ *SECADM *JOBCTLNOCRITICAL
048334/APPSVC/NIGHTLY02APPSVCAPPSVCQBATCHRUN*ALLOBJ *SECADM *JOBCTLNOCRITICAL
048402/BATCHUSR/RUNJRNRPTBATCHUSRQSECOFRQBATCHRUN*ALLOBJ *SECADM *JOBCTL *IOSYSCFGYESCRITICAL
048510/SCHEDULER/AUDRPTSCHEDULERAUDPROFQBATCH2RUN*SECADM *AUDITNOHIGH
048612/OPUSER/DLYINVOPUSEROPUSERQBATCHMSGW*JOBCTLNOMEDIUM
048701/APPUSR/DLYSHIPAPPUSRSHIPSVCAPPSBSRUN*NONEYESREVIEW

🔎

Findings: Two APPSVC jobs running under *ALLOBJ *SECADM *JOBCTL — any compromise of this service account affects the entire system. Job 048402/BATCHUSR/RUNJRNRPT shows an identity switch from BATCHUSR to QSECOFR — warrants immediate investigation. Job 048701/APPUSR/DLYSHIP switched to SHIPSVC (no special authority) but the switch requires baseline confirmation.

6.2 Authority Adoption Exposure by Library

-- Summarizes adopted-authority program exposure by library
-- Useful for scoping which application libraries carry the most adoption risk
SELECT
    P.PROGRAM_LIBRARY                                AS LIBRARY,
    COUNT(*)                                         AS ADOPTING_OBJECTS,
    SUM(CASE WHEN P.OBJECT_TYPE = '*PGM'    THEN 1 ELSE 0 END) AS PROGRAMS,
    SUM(CASE WHEN P.OBJECT_TYPE = '*SRVPGM' THEN 1 ELSE 0 END) AS SERVICE_PROGRAMS,
    SUM(CASE WHEN U.SPECIAL_AUTHORITIES LIKE '%*ALLOBJ%'
             THEN 1 ELSE 0 END)                      AS ALLOBJ_OWNER_COUNT,
    SUM(CASE WHEN U.SPECIAL_AUTHORITIES LIKE '%*SECADM%'
             THEN 1 ELSE 0 END)                      AS SECADM_OWNER_COUNT,
    LISTAGG(DISTINCT P.PROGRAM_OWNER, ', ')
        WITHIN GROUP (ORDER BY P.PROGRAM_OWNER)      AS OWNERS
FROM QSYS2.PROGRAM_INFO AS P
JOIN QSYS2.USER_INFO AS U
    ON U.AUTHORIZATION_NAME = P.PROGRAM_OWNER
WHERE P.USER_PROFILE  = '*OWNER'
  AND P.OBJECT_TYPE   IN ('*PGM', '*SRVPGM')
  AND P.PROGRAM_OWNER <> 'QSYS'
GROUP BY P.PROGRAM_LIBRARY
ORDER BY ALLOBJ_OWNER_COUNT DESC, ADOPTING_OBJECTS DESC;

7. Remediation and Operational Guidance

Phase 1 — Baseline the Batch Environment

  1. Run Query 3.1 to establish which subsystems carry batch workload and identify those with IDENTITY_MISMATCHES > 0.
  2. Run Query 3.3 and 3.4 to compare submitted vs. running user populations — any profile that appears running but not submitting is a service account being used as a run-under target.
  3. Run Query 4.1 to identify jobs running under profiles with special authority. Document which have a legitimate business justification.

Phase 2 — Investigate Identity Switches

  1. Run Query 4.2 to list all jobs where running user differs from submitted user.
  2. For each job, determine whether the switch was intended by design (e.g., SBMJOB USER(APPSVC)) or unexpected.
  3. For unexpected switches, enable *JOBDTA auditing and review JS journal entries via SYSTOOLS.AUDIT_JOURNAL_JS().

Phase 3 — Reduce Authority Adoption Surface

  1. Run Query 5.3 to quantify how many adopting programs are owned by profiles with *ALLOBJ or *SECADM.
  2. For each CRITICAL or HIGH program from Query 5.1, evaluate whether adoption is required or can be refactored.
  3. Run Query 5.4 for service programs — harder to trace and should be reviewed against calling programs' call stacks.

Phase 4 — Harden Service Account Profiles

ActionCommand
Remove unnecessary special authoritiesCHGUSRPRF USRPRF(profile) SPCAUT(*NONE)
Restrict run-under targeting (IBM i 7.6)CHGFCNUSG FCNID(QIBM_RUN_UNDER_USER_NO_AUTH) USER(profile) USAGE(*DENIED)
Enable auditing on the service accountCHGUSRAUD USRPRF(profile) AUDLVL(*JOBBAS *OBJMGT)
Disable password-based sign-on if batch-onlyCHGUSRPRF USRPRF(profile) PASSWORD(*NONE)

Phase 5 — Ongoing Monitoring

  • Schedule Query 6.1 daily — alert on any new CRITICAL or HIGH entries.
  • Schedule Query 4.2 weekly — investigate any new identity switch combinations not in the approved baseline.
  • Schedule Query 5.3 monthly — alert when new *ALLOBJ-owned adopting programs appear.
  • Integrate QSYS2.ACTIVE_JOB_INFO monitoring into SIEM pipelines for real-time batch workload visibility.

8. Quick Reference

ItemValue / Command
Active job viewQSYS2.ACTIVE_JOB_INFO
User profile viewQSYS2.USER_INFO
Program attributes viewQSYS2.PROGRAM_INFO
Job queue entries viewSYSTOOLS.JOB_QUEUE_ENTRIES
Job journal entriesSYSTOOLS.AUDIT_JOURNAL_JS()
Submitted user fieldJOB_USER in ACTIVE_JOB_INFO
Running user fieldAUTHORIZATION_NAME in ACTIVE_JOB_INFO
Batch job type filterJOB_TYPE = 'BCH'
Authority adoption attributeUSER_PROFILE = '*OWNER' in PROGRAM_INFO
Enable job auditingCHGSYSVAL SYSVAL(QAUDLVL) VALUE('*JOBDTA')
Enable per-profile auditingCHGUSRAUD USRPRF(profile) AUDLVL(*JOBBAS)
Restrict run-under (7.6)CHGFCNUSG FCNID(QIBM_RUN_UNDER_USER_NO_AUTH) USER(profile) USAGE(*DENIED)
Remove batch-only passwordCHGUSRPRF USRPRF(profile) PASSWORD(*NONE)
Disable a service accountCHGUSRPRF USRPRF(profile) STATUS(*DISABLED)

Document Location

Worldwide

[{"Type":"MASTER","Line of Business":{"code":"LOB68","label":"Power HW"},"Business Unit":{"code":"BU070","label":"IBM Infrastructure"},"Product":{"code":"SWG60","label":"IBM i"},"ARM Category":[{"code":"a8m0z0000000CHyAAM","label":"Security"}],"ARM Case Number":"","Platform":[{"code":"PF012","label":"IBM i"}],"Version":"and future releases;7.4.0;7.5.0;7.6.0"}]

Document Information

Modified date:
30 July 2026

UID

ibm17281951