An evidence-based assessment of change management, access governance, segregation of duties, privileged and emergency access, integrations, managed bundles, and service-organization oversight for the NetSuite production environment.
This review assessed the NetSuite production environment against the information-technology general controls (ITGC) an external auditor will test in a first-year SOX 404 engagement, and against the operational practices expected of a company preparing for public-market scrutiny. The assessment was conducted by direct, read-only interrogation of the live system — role and permission tables, login audit trails, script and deployment inventories, change-history records — rather than by questionnaire or interview.
The conclusion is straightforward: the account has a strong technical audit surface but operating practices that would not survive a SOX 404 walkthrough today. The audit trail exists; the discipline around it does not yet. None of the deficiencies identified are structural, and all are remediable within one to two quarters. Section 9 sequences that work.
| # | Finding | SOX relevance | Effort |
|---|---|---|---|
| 1 | Sixteen inactive employees retain Administrator role assignments; fifteen of twenty-one access-enabled users show no login in ninety days. | Terminated / dormant access — the most common ITGC failure | Low |
| 2 | Seven active Administrators for twenty-one users (33%), with two admin identity pairs sharing a single email address. | Privileged access; non-attributable actions | Medium |
| 3 | Segregation-of-duties conflicts in finance roles, most notably vendor-master edit combined with vendor payment at Full level in the A/P Analyst roles. | Fictitious-vendor exposure; first item auditors sample | Medium |
| 4 | Change management is UI-driven and direct-in-production: 769 DEBUG deployments, 18 TESTING-status deployments live, a production "hotfix" folder, 91% of scripts undocumented. | Absence of change-management ITGC | High |
| 5 | Key financial approval workflows are in NOTINITIATING status — documented controls that are not operating. | Control documented but not operating | Low–Medium |
Readiness reviews conventionally lead with deficiencies. The following affirmative findings were verified with the same rigor and materially reduce the remediation surface.
| Ref | Verified strength | Evidence |
|---|---|---|
| S-1 | Two-factor authentication is enforced for UI login. | Observed WrongSecondFactor failure events and loginchallenge request URIs in loginaudit. |
| S-2 | Zero inactive employees hold enabled login access. | employee where giveaccess='T': all 21 rows active. |
| S-3 | No brute-force or credential-stuffing patterns. | 196 successes / 3 failures in 90 days; failures are isolated password and second-factor errors. |
| S-4 | No non-Administrator role combines user provisioning with transaction posting. | rolepermissions scan for ADMI_MANAGEUSERS / ADMI_MANAGEROLES against posting permissions: zero rows. |
| S-5 | Payroll segregation is a non-issue. | No active role grants payroll-run permission. |
| S-6 | No RESTlet is exposed without authentication. | 183 deployed RESTlets; zero with isonline='T'. |
| S-7 | A working SDF deployment pipeline exists. | SDF context observed in systemnote during one ~25-day window. |
| S-8 | Script naming and folder discipline are reasonable. | Consistent scriptid prefixes; organized File Cabinet structure. |
All findings carry stable identifiers for tracking through remediation. Severity reflects a combination of audit impact and exploitability; effort estimates assume the current team.
| ID | Severity | Finding | Section | Effort |
|---|---|---|---|---|
| AG-1 | High | 16 inactive employees retain Administrator role assignments (reactivation risk). | § 1 | Low |
| AG-2 | High | 15 of 21 access-enabled users have zero logins in 90 days. | § 1 | Low |
| AG-3 | Medium | Role TEST_DELETE_ME (id 2087) is active and assigned to a user. | § 1 | Low |
| SD-1 | High | A/P Analyst roles (1132, 1659) grant vendor-master Full and Pay Bills Full concurrently. | § 2 | Medium |
| SD-2 | Medium | CFO / Controller-family roles stack journal posting, vendor payment, vendor-master edit, and bank reconciliation. | § 2 | Medium |
| PA-1 | High | Two admin identity pairs share single email addresses; one audited admin email matches no listed identity. | § 3 | Low |
| PA-2 | High | 33% administrator ratio (7 of 21 users). | § 3 | Medium |
| EA-1 | Medium | No break-glass account or emergency-access procedure exists. | § 4 | Low |
| CM-1 | High | No change-management SOP; changes are UI-driven and direct-in-production, including a named "hotfix" script. | § 5 | High |
| CM-2 | Medium | Production hygiene: 769 DEBUG deployments, 18 TESTING deployments live, 91% of scripts undocumented, financial approval workflows NOTINITIATING. | § 5 | Medium |
| IN-1 | Medium | 33 Suitelets deployed with anonymous (available-without-login) access. | § 7 | Medium |
| IN-2 | Medium | ChatGPT and Claude AI integration records enabled with no observed usage and no documented owner. | § 7 | Low |
employeerolesforsearch (columns role, entity); grants in rolepermissions (permission levels 1 = View through 4 = Full).loginaudit; the six active users are enumerated in § 3.AG-1 (High). Sixteen inactive employees retain Administrator role assignments. Their access flag is off and the employees are inactive, but the role row persists — a single reactivation restores full administrative control. The population is largely legacy demonstration staff (e.g., A. Rymarquis, E. Goyena, P. Cutler, R. Rote, T. Cabral; predominantly @netsuite.com addresses). Under SOX this is a terminated-access deficiency regardless of the disabled flag, because the compensating state (inactive + no access) is not itself a controlled, attested condition.
AG-2 (High). Fifteen enabled accounts with no login in ninety days. Dormant enabled access is a standard ITGC deficiency: it widens the credential attack surface and demonstrates the absence of a periodic access review.
AG-3 (Medium). A role named TEST_DELETE_ME (internal id 2087) is active and assigned to a user — direct evidence that role lifecycle management is informal.
permissions-audit process definition can be productized into this quarterly run. The first review should be executed immediately to clear AG-1 through AG-3.systemnote on employee records and rolepermissions.datemodified / modifiedby.The permission grants below were read directly from rolepermissions and represent conflicting duties concentrated in single roles. Levels: 1 View · 2 Create · 3 Edit · 4 Full.
| Role (internal id) | Journal | Pay Bills | Vendor Master | Bank Rec | Conflict pattern |
|---|---|---|---|---|---|
| CFO (41, standard · 1 user) | 4 | 4 | 4 | 4 | All three conflict sets; 240 of 338 permissions at Full |
| MCP — Custom CFO (1984, custom · 1 user) | 4 | 4 | 4 | 4 | All three conflict sets; 170 of 234 at Full |
| AI Companion Controller (2093, custom) | 4 | 3 | 4 | 4 | JE + bank rec; vendor edit + payment |
| CEO (8, standard) | 4 | 4 | 4 | 3 | Vendor edit + payment; JE + bank rec |
| EP Processor (1651, custom) | 4 | 4 | 1 | — | Journal Full + Pay Bills Full in one role |
| SS RT PRM — Controller (1664 · 2 users) / RT PRM — Controller (1136) | 3 | 3 | 4 | 4 | JE + bank rec; vendor edit + payment |
| SS RT PRM — Accountant (1661) | 4 | 2 | 2 | 4 | Journal Full + bank-rec Full |
| RT PRM — A/P Analyst (1132) / SS RT PRM — A/P Analyst (1659) | 3 | 4 | 4 | — | Vendor-master edit + vendor payment — fictitious-vendor exposure (SD-1) |
| Accountant (1) / Bookkeeper (6) | 3 | 3 | 3 | 3 | All duties at Edit or above |
ADMI_MANAGEUSERS / ADMI_MANAGEROLES) with transaction posting, and no active role grants payroll execution. Sensitive permissions in circulation that warrant a named owner: ADMI_VIEW_PAYMENT_CARD_TOKENS, ADMI_VIEW_GENERAL_TOKENS, LIST_EMPLOYEESSN, LIST_VENDOR_ACH.
Seven identities hold active Administrator access: A. Traynor (141), B. Morgan (149), C. Schmitz (3900), J. Bailey (3871), K. Glass (−5), T. Dietrich (158), T. Dietrich (3894).
loginaudit, role = 3, grouped by email address. Note that partner-admin@example.com does not correspond to any of the seven listed admin identities — see PA-1.PA-1 (High). Two admin identity pairs share a single mailbox (K. Glass and C. Schmitz → partner-admin@example.com; A. Traynor and B. Morgan → partner-admin@example.com). Shared mailboxes on privileged identities break attribution: an auditor cannot tie an administrative action to a person, which undermines every downstream control that relies on the audit trail. Additionally, partner-admin@example.com appears in the admin login audit but matches no listed admin identity — this must be reconciled.
PA-2 (High). A 33% administrator ratio. The enterprise norm is two to three named administrators plus a sealed break-glass account (§ 4).
PA-3 (Medium, folded into PA-2 remediation). Day-to-day work is being performed under the Administrator role (549 admin sessions across the two primary identities in 180 days). Routine work belongs in scoped roles; administrator sessions should be rare, purposeful, and individually explainable.
loginaudit filtered to role 3. Every administrator session should have an explanation; most months, the correct count is near zero.Current state (EA-1, Medium): no break-glass account exists — no employee record matches emergency-access naming patterns, and no procedure is documented. In practice, "emergency access" today means one of seven administrators logs in, which is indistinguishable from routine use and therefore provides neither control nor evidence.
systemnote and loginaudit filtered to the break-glass user id) and file the review.systemnote.context over 365 days: UIF (interactive UI changes — dominant at roughly 6,193 events), SWF, MPR, SCH, SLT, RST, SDF (a single ~25-day window), OTR. No sandbox-copy context is discoverable in this table.customscript_de_dept_hotfix_ss — direct evidence of in-production hotfixing, authored under a developer identity that duplicates another identity.CM-1 (High) — Adopt a change-management SOP. Every production customization change requires: a request record, an approver who is not the developer, testing evidence from sandbox, and a deployment record. At this team size, a lightweight change register (a custom record type suffices) is adequate — the control is the discipline, not the tooling. The register must reconcile to systemnote; that reconciliation, performed monthly, is itself the detective control that proves completeness.
CM-2 — Standardize on SDF / SuiteCloud CLI with git as the only path for script and object changes. The single verified SDF window proves the pipeline already works. Git history plus pull-request approvals then generate change-control evidence as a by-product of normal work — the cheapest evidence a control can produce.
CM-3 — Production hygiene sweep (approximately one afternoon): reduce the 769 DEBUG deployments to ERROR or AUDIT level; release or remove the 18 TESTING deployments; migrate and retire the hotfix folder; add descriptions to all locally-owned scripts.
CM-4 — Reinstate the financial approval workflows, or formally retire them and document the replacement control. A documented-but-dormant automated control is a finding waiting to be written; the auditor's question — "was this control operating during the period?" — currently has an unfavorable answer.
CM-5 — Document the future-dated file timestamps so the anomaly carries a written explanation rather than surfacing unexplained during fieldwork.
bundleinstallation table is not query-exposed in this account, and the Installed Bundles page did not render for programmatic capture. A definitive bundle inventory therefore requires one manual step: Customization → SuiteBundler → Search & Install Bundles → List, exported. The footprint analysis below is verified; the installation-level detail (version, update policy, install date) is not.
The customization footprint — 437 custom record types, 151 custom lists, and a script population of roughly 1,100 — is majority bundle-owned. Attribution by scriptid prefix (the customsegment.frombundle column is empty account-wide and cannot be relied upon):
| Bundle / suite | Prefix evidence | Function |
|---|---|---|
| Fixed Assets Management | _FAM_ / _NCFAR_ | Asset lifecycle, depreciation — financially significant |
| Electronic Bank Payments | _2663_ / _9572_ / _9997_ / _15529_ | Payment file generation — financially significant |
| SuiteTax Engine & Reporting | _STE_ / _STR_ | Tax determination — financially significant |
| Ship Central / PackShip | _PACKSHIP_ | Fulfillment operations |
| Manufacturing Mobile | _MFGMOB_ | Shop-floor operations |
| Benchmark 360 · Cash 360 · Item 360 | _B360_ / _CASH360_ / _ITEM360_ | Analytics — candidates for retirement review |
| Atlas / SuiteSuccess starter content | _ATLAS_ | Starter-edition records and demonstration content |
bundle-impact-review process should be run per bundle ahead of an IPO-readiness cleanup.| Integration application | State | Created | Observed usage (90 d) |
|---|---|---|---|
| SuiteTalk REST | Enabled | 2026-08-16 | None |
| ChatGPT | Enabled | 2026-08-31 † | None |
| Claude AI | Enabled | 2026-08-31 † | None |
| SuiteCloud Development Integration | Enabled | 2026-09-04 † | None (SDF window predates) |
| Default Web Services Integrations | Enabled | 2028-01-22 † | None |
† Future-dated creation timestamps as returned by integrationapp.createddate — the same timestamp anomaly noted in CM-5. Zero OAuth or token logins were observed in the 90-day login audit; the integration layer is configured but dormant.
isonline='T') — finding IN-1.IN-1 (Medium-High). Thirty-three anonymous-access Suitelets are live production entry points requiring no authentication. Each requires individual review: business justification, data exposed, input validation. Any that cannot justify their exposure should be taken offline. The enumeration query is in Appendix B.
IN-2 (Medium). The ChatGPT and Claude AI integration records are enabled with no observed usage and no documented owner. Enabled-and-unused is the least defensible state — attack surface without accountability. Block them until an owner claims them, and document the organization's AI-access policy in either case; IPO diligence questionnaires now routinely probe AI data flows.
IN-3 (Medium). No dedicated service accounts exist. When integrations activate, each must run under a dedicated integration user holding a minimum-permission, web-services-only role (iswebserviceonlyrole='T') — never under a person's credentials, and never under Administrator.
Maintain an integration register (name → owner → purpose → auth method → token → role → review date); recertify tokens quarterly alongside the UAR; adopt a standing rule that no access token is ever minted against the Administrator role. Token inventory is not query-exposed (Appendix C) — the quarterly recertification uses Setup → Users/Roles → Access Tokens.
NetSuite is a SOX-relevant outsourced service organization; management's control set must include an annual, evidenced review of Oracle NetSuite's SOC 1 Type 2 report (and SOC 2 where relevant to security commitments).
| Typical NetSuite CUEC theme | Mapped control in this program |
|---|---|
| Customer manages user access and deprovisioning | Quarterly UAR + JML procedure (§ 1) |
| Customer configures roles and permissions appropriately | SoD matrix + quarterly re-scan (§ 2) |
| Customer restricts administrative access | Admin reduction + monthly role-3 login review (§ 3); break-glass procedure (§ 4) |
| Customer controls changes to configurations and customizations | Change SOP + SDF pipeline + register reconciliation (§ 5) |
| Customer manages third-party components and API access | Bundle register (§ 6); integration register + token recertification (§ 7) |
| Customer enforces authentication policy | 2FA verified operating (S-1); monitored via login audit |
TEST_DELETE_ME id 2087 (AG-3).permissions-audit and bundle-impact-review process definitions so each run produces evidence automatically.| Cadence | Control activity | Evidence artifact | Owner (proposed) |
|---|---|---|---|
| Monthly | Administrator-session review (role 3 login audit) | Reviewed login extract with annotations | Controller |
| Monthly | Executive-role JE & vendor-change review (compensating control) | Signed review memo | Controller / CFO peer |
| Monthly | Change register ↔ systemnote reconciliation | Reconciliation worksheet | IT / NetSuite admin |
| Quarterly | User access review (users × roles × last login) | Owner attestations | Functional owners |
| Quarterly | SoD re-scan (Appendix B queries) | Scan output + diff vs. prior quarter | IT / NetSuite admin |
| Quarterly | Token & integration recertification | Register with review dates | IT / NetSuite admin |
| Semi-annual | Break-glass procedure test | Test record + session review | CFO + IT |
| Annual | NetSuite SOC 1 review + CUEC mapping; other service organizations | SOC review memo | Controller |
| Annual | Bundle register review / retirement pass | Updated register | IT / NetSuite admin |
The review was executed entirely read-only on 2026-08-24 against the live production account, using SuiteQL queries, record-catalog introspection, and login/system audit tables. Three parallel research investigations covered (i) access governance and SoD, (ii) integrations and privileged access, and (iii) change management and customization footprint; their outputs were then independently spot-verified with direct queries before inclusion. No records, roles, permissions, scripts, or files were modified in the course of this review.
bundleinstallation unavailable and customsegment.frombundle empty account-wide, bundle ownership of objects was attributed by scriptid prefix convention. Confidence is high for well-known suites (FAM, EBP, SuiteTax) but the manual bundle export (§ 6) remains the authoritative source.All queries below were verified working in this account on the review date. They are the substrate of the quarterly monitoring controls in § 10 — re-running them and retaining the diff is the control.
-- The role-assignment table (two columns only)
SELECT role, entity FROM employeerolesforsearch;
-- Users with enabled login access
SELECT id, entityid, email, giveaccess, isinactive
FROM employee
WHERE giveaccess = 'T';
-- Sensitive grants at Edit level or above, per role
SELECT role, permkey, permlevel
FROM rolepermissions
WHERE permkey IN ('TRAN_JOURNALENTRY','TRAN_PAYBILLS','LIST_VENDOR',
'TRAN_BANKRECONCILIATION','ADMI_MANAGEUSERS','ADMI_MANAGEROLES',
'LIST_EMPLOYEESSN','LIST_VENDOR_ACH',
'ADMI_VIEW_PAYMENT_CARD_TOKENS','ADMI_VIEW_GENERAL_TOKENS')
AND permlevel >= 3;
-- Admin-role logins by email address
-- NOTE: COUNT(DISTINCT user) combined with date filters fails on loginaudit
-- in this account; group by emailaddress instead.
SELECT emailaddress, COUNT(*) AS logins
FROM loginaudit
WHERE role = 3
GROUP BY emailaddress
ORDER BY COUNT(*) DESC;
SELECT s.name, s.scriptid, d.scriptid AS deploymentid
FROM scriptdeployment d
JOIN script s ON s.id = d.script
WHERE d.isdeployed = 'T'
AND d.isonline = 'T'
AND s.scripttype = 'SCRIPTLET';
-- Integration application inventory
SELECT id, name, state, createddate FROM integrationapp;
-- DEBUG-level deployments live in production
SELECT COUNT(*) FROM scriptdeployment
WHERE loglevel = 'DEBUG' AND isdeployed = 'T';
-- External deployment surface by script type
SELECT s.scripttype,
COUNT(*) AS deployments,
SUM(CASE WHEN d.isonline = 'T' THEN 1 ELSE 0 END) AS available_without_login
FROM scriptdeployment d
JOIN script s ON s.id = d.script
WHERE d.isdeployed = 'T'
AND s.scripttype IN ('RESTLET','SCRIPTLET')
GROUP BY s.scripttype;
In the interest of full transparency, the following could not be verified programmatically. Do not re-attempt these query paths; use the manual verification listed.
| Attempted | Result | Manual verification path |
|---|---|---|
bundleinstallation, bundle tables; Installed Bundles page scrape | Not query-exposed / page did not render programmatically | Customization → SuiteBundler → Search & Install Bundles → List (export) |
tokenpassport, accesstoken, token tables | Not query-exposed | Setup → Users/Roles → Access Tokens |
integration table | Invalid search type — superseded by integrationapp (which lacks auth-flag columns) | Integration record UI for auth-method detail |
COUNT(DISTINCT user) with date filters on loginaudit | "Invalid or unsupported search" | Group by emailaddress instead (B.3) |
| Per-object change-velocity counts (custom fields, records, searches) | Invalidated by a mass-touch event on timestamps circa 2026-08-12 | Prospective measurement once the change register (§ 5) operates |
| Per-user 2FA enrollment status | No queryable table; enforcement inferred from challenge events | Setup → Users/Roles → Two-Factor Authentication |
| Sandbox-to-production copy evidence | No sandbox context in systemnote; provisioning settings not query-exposed | Setup → Company → Sandbox Accounts |
| Source | Role in this review |
|---|---|
Live SuiteQL interrogation of role, employee, employeerolesforsearch, rolepermissions, loginaudit, script, scriptdeployment, systemnote, integrationapp, workflow, customfield, customrecordtype, mediaitemfolder | Primary evidence — all counts and identifiers |
| Three parallel read-only research investigations (access governance & SoD; integrations & privileged access; change management & customization footprint), 2026-08-24 | Breadth survey; all headline figures independently re-verified before inclusion |
| Sonar account field notes for TD3016323 (schema quirks, bundle-prefix conventions, prior verified facts) | Accelerant and cross-check; superseded by live data wherever they conflict |
| sox-ipo-readiness-review-2026-08-24.md (companion markdown edition, same date) | Working-format predecessor of this document; content-identical findings |
| Branding & Formatting Guidelines — Precision Slate | Design system governing this document's typography, palette, and layout |