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
| Characteristic | Interactive Job | Batch Job |
|---|---|---|
| Initiation | User sign-on | SBMJOB, job scheduler, or prestart job |
| Audit trigger | Sign-on event (type T) | Job start event (type JS) — only if *JOBBAS/*JOBDTA auditing active |
| Running user | Always the signed-on user | May differ from submitting user (USER parameter) |
| Duration | Bounded by interactive session | Can run hours, days, or indefinitely |
| Program authority | User's own authority | May include adopted authority from program owners |
| Visibility | Always in active job table | May 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
| Field | Source View | Meaning |
|---|---|---|
| JOB_USER | QSYS2.ACTIVE_JOB_INFO | User profile under which the job was submitted — the submitting identity |
| AUTHORIZATION_NAME | QSYS2.ACTIVE_JOB_INFO | User profile the job is currently running under — may differ from JOB_USER |
| USER_NAME | SYSTOOLS.AUDIT_JOURNAL_JS | User attributed in the audit journal entry — typically the submitting user |
| EFFECTIVE_USER_PROFILE | SYSTOOLS.AUDIT_JOURNAL_JS | User 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
| Element | Description |
|---|---|
| Program attribute | USER_PROFILE = *OWNER |
| Effect | Adds program owner's authority to the call stack for the duration of the program call |
| Chain behavior | Adopted authority accumulates across nested program calls — each *OWNER program adds its owner's authority |
| Risk condition | Owner holds *ALLOBJ or other special authority — effective authority during execution may far exceed the running user's nominal profile |
| Audit gap | Authority 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
| SUBSYSTEM | SUBSYSTEM_LIBRARY_NAME | JOB_COUNT | UNIQUE_USERS | UNIQUE_CURRENT_USERS | IDENTITY_MISMATCHES | RUNNING | WAITING_ON_MSG |
|---|---|---|---|---|---|---|---|
| QBATCH | QSYS | 142 | 18 | 23 | 7 | 98 | 44 |
| QBATCH2 | QSYS | 31 | 5 | 6 | 2 | 31 | 0 |
| APPSBS | APPSLIB | 14 | 3 | 3 | 0 | 14 | 0 |
| QSYSWRK | QSYS | 9 | 9 | 9 | 0 | 9 | 0 |
🔎
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_NAME | SUBMITTED_BY | RUNNING_AS | SUBSYSTEM | JOB_STATUS | SPECIAL_AUTHORITIES | RISK_LEVEL |
|---|---|---|---|---|---|---|
| 047821/APPSVC/NIGHTLY01 | APPSVC | APPSVC | QBATCH | ACTIVE | *ALLOBJ *SECADM *JOBCTL | CRITICAL |
| 047854/APPSVC/NIGHTLY02 | APPSVC | APPSVC | QBATCH | ACTIVE | *ALLOBJ *SECADM *JOBCTL | CRITICAL |
| 047901/JDOE/REPORT01 | JDOE | BATCHSVC | QBATCH | ACTIVE | *JOBCTL | MEDIUM |
| 047912/BATCHSVC/SYNC01 | BATCHSVC | BATCHSVC | QBATCH2 | JOBQ | *SAVSYS *JOBCTL | MEDIUM |
🔎
Findings: APPSVC holds *ALLOBJ with 2 active overnight batch jobs — highest risk. The JDOE → BATCHSVC 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
| LIBRARY | PROGRAM_NAME | OBJECT_TYPE | OWNER | CREATED | OWNER_AUTHORITIES | RISK_LEVEL |
|---|---|---|---|---|---|---|
| APPLIB | POSTCLOSE | *PGM | QSECOFR | 2019-03-14 | *ALLOBJ *SECADM *JOBCTL | CRITICAL |
| APPLIB | NITECLOSE | *PGM | APPSVC | 2021-06-01 | *ALLOBJ *SECADM | CRITICAL |
| RPTLIB | RUNJRNRPT | *PGM | QSYSOPR | 2020-11-20 | *JOBCTL *SAVSYS | MEDIUM |
| UTILLIB | CLROUTQ | *PGM | QSECOFR | 2018-05-10 | *ALLOBJ *SECADM *JOBCTL | CRITICAL |
🔎
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_NAME | SUBMITTED_BY | RUNNING_AS | SUBSYSTEM | JOB_STATUS | SPECIAL_AUTHORITIES | IDENTITY_SWITCHED | RISK_LEVEL |
|---|---|---|---|---|---|---|---|
| 048201/APPSVC/NIGHTLY01 | APPSVC | APPSVC | QBATCH | RUN | *ALLOBJ *SECADM *JOBCTL | NO | CRITICAL |
| 048334/APPSVC/NIGHTLY02 | APPSVC | APPSVC | QBATCH | RUN | *ALLOBJ *SECADM *JOBCTL | NO | CRITICAL |
| 048402/BATCHUSR/RUNJRNRPT | BATCHUSR | QSECOFR | QBATCH | RUN | *ALLOBJ *SECADM *JOBCTL *IOSYSCFG | YES | CRITICAL |
| 048510/SCHEDULER/AUDRPT | SCHEDULER | AUDPROF | QBATCH2 | RUN | *SECADM *AUDIT | NO | HIGH |
| 048612/OPUSER/DLYINV | OPUSER | OPUSER | QBATCH | MSGW | *JOBCTL | NO | MEDIUM |
| 048701/APPUSR/DLYSHIP | APPUSR | SHIPSVC | APPSBS | RUN | *NONE | YES | REVIEW |
🔎
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
- Run Query 3.1 to establish which subsystems carry batch workload and identify those with
IDENTITY_MISMATCHES > 0. - 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.
- 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
- Run Query 4.2 to list all jobs where running user differs from submitted user.
- For each job, determine whether the switch was intended by design (e.g.,
SBMJOB USER(APPSVC)) or unexpected. - For unexpected switches, enable
*JOBDTAauditing and reviewJSjournal entries viaSYSTOOLS.AUDIT_JOURNAL_JS().
Phase 3 — Reduce Authority Adoption Surface
- Run Query 5.3 to quantify how many adopting programs are owned by profiles with
*ALLOBJor*SECADM. - For each CRITICAL or HIGH program from Query 5.1, evaluate whether adoption is required or can be refactored.
- 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
| Action | Command |
|---|---|
| Remove unnecessary special authorities | CHGUSRPRF 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 account | CHGUSRAUD USRPRF(profile) AUDLVL(*JOBBAS *OBJMGT) |
| Disable password-based sign-on if batch-only | CHGUSRPRF 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_INFOmonitoring into SIEM pipelines for real-time batch workload visibility.
8. Quick Reference
| Item | Value / Command |
|---|---|
| Active job view | QSYS2.ACTIVE_JOB_INFO |
| User profile view | QSYS2.USER_INFO |
| Program attributes view | QSYS2.PROGRAM_INFO |
| Job queue entries view | SYSTOOLS.JOB_QUEUE_ENTRIES |
| Job journal entries | SYSTOOLS.AUDIT_JOURNAL_JS() |
| Submitted user field | JOB_USER in ACTIVE_JOB_INFO |
| Running user field | AUTHORIZATION_NAME in ACTIVE_JOB_INFO |
| Batch job type filter | JOB_TYPE = 'BCH' |
| Authority adoption attribute | USER_PROFILE = '*OWNER' in PROGRAM_INFO |
| Enable job auditing | CHGSYSVAL SYSVAL(QAUDLVL) VALUE('*JOBDTA') |
| Enable per-profile auditing | CHGUSRAUD USRPRF(profile) AUDLVL(*JOBBAS) |
| Restrict run-under (7.6) | CHGFCNUSG FCNID(QIBM_RUN_UNDER_USER_NO_AUTH) USER(profile) USAGE(*DENIED) |
| Remove batch-only password | CHGUSRPRF USRPRF(profile) PASSWORD(*NONE) |
| Disable a service account | CHGUSRPRF USRPRF(profile) STATUS(*DISABLED) |
Document Location
Worldwide
Was this topic helpful?
Document Information
Modified date:
30 July 2026
UID
ibm17281951