Sample output from the Sensitive-Data Hazard Scan — Custom Field Definitions prompt in the Sonar AI Prompt Library, run against a NetSuite test account. Every name and number here is test data. Back to the post · The library
Security Review · Configuration Audit · September 4, 2026

Sensitive-Data
Hazard Scan

A pattern-based review of every custom field definition in this NetSuite account, identifying fields that store credentials or duplicate regulated personal data outside native, governed fields. Counts only — no stored values were retrieved into this report.

Verdict: action required. Live plaintext credentials were confirmed in two custom fields, populated on 17 records. One secret surfaced during scanning and must be treated as exposed.

AccountTD3096877 · Production
Requested byEric Ackbury
MethodRead-only SuiteQL · metadata + counts
Performed bySonar AI v0.4.0
01

Executive summary

2,485 custom field definitions were scanned. Two live hazards were confirmed — both store credential material in plain, unencrypted text fields readable by any role with record access.

0
Fields scanned
2,406 stored
0
High · populated
17 records affected
0
Medium · dormant
0 records today
0
Regulated-data hits
3 populated
Key finding

Plaintext API credentials are live in this account today. The field custrecord_filing_authorization_cred holds what appears to be an active client id + secret pair in JSON on both records of the Online Filing Authorization record type. A second field, custrecord_ccp_gateway_cred_id, is populated on all 15 Additional Credential records. Neither field is encrypted, masked, or restricted beyond ordinary record permissions.

During schema verification, the credential value surfaced in diagnostic output — treat that secret as exposed and rotate it regardless of any other action taken.

02

Scan funnel

How 2,485 field definitions were reduced to 2 confirmed live hazards. Each stage is fully reproducible from the queries in section 05.

Custom field definitions
2,485
↳ pattern dictionaries: credentials + regulated data −2,326
Raw pattern hits
159 (18 + 141)
↳ false-positive triage: Author≠Auth, actiVATion≠VAT, template text −146
Verified hazard fields
13
↳ population check: count-only queries against host tables −11
Live high-severity hazards
2 fields · 17 records
03

Findings

Thirteen fields survived triage. Filter by severity or search any scriptid, label, record type, or owner.

Showing 13 of 13 findings
HighCUSTRECORD_FILING_AUTHORIZATION_CREDid 820● 2 of 2 populated
Label · Type
“Credentials” · Text Area, stored
Record type
CUSTOMRECORD_FILING_AUTHORIZATION — Online Filing Authorization (160)
Owner
Eduardo Souto (1548)
Holds a plaintext JSON client id + secret pair. Surfaced in diagnostic output during this scan — rotate at the issuing provider immediately. Top remediation priority.
HighCUSTRECORD_CCP_GATEWAY_CRED_IDid 2640● 15 of 15 populated
Label · Type
“Additional Credential ID” · Free-Form Text, stored
Record type
CUSTOMRECORD_CCP_GATEWAY_ADD_CRED — Additional Credential (507)
Owner
Dave Belmonte (1576)
Values deliberately not read. If these are gateway secrets rather than reference ids, escalate to the same treatment as the finding above. Manual classification of one record recommended.
MediumCUSTRECORD_PAYU_CONFIG_REC_API_KEYid 2630○ 0 rows
Label · Type
“API Key” · Free-Form Text, stored
Record type
CUSTOMRECORD_CCP_PAYU_CONFIG_REC — PayU Account Info & Credentials (504)
Owner
Dave Belmonte (1576)
Payment-gateway bundle field designed to hold a secret in plain text. Empty today — becomes high-severity the moment PayU is configured. Restrict the record type now.
MediumCUSTRECORD_ASIAPAY_CONF_REC_HASH_SECRETid 2635○ 0 rows
Label · Type
“Secure Hash Secret” · Free-Form Text, stored
Record type
CUSTOMRECORD_CCP_ASIAPAY_CONFIG_REC — AsiaPay Account Info (506)
Owner
Dave Belmonte (1576)
MediumCUSTRECORD_ASIAPAY_DIR_CONF_HASH_SECRETid 2653○ 0 rows
Label · Type
“Secure Hash Secret” · Free-Form Text, stored
Record type
CUSTOMRECORD_CCP_ASIAPAY_DIRECT_CONFIG — AsiaPay Payment Account Info (510)
Owner
Dave Belmonte (1576)
MediumCUSTRECORD_NS_SC_EXT_SN_S_EMAILid 1447● 3 of 3 populated
Label · Type
“Email” · Email Address, stored
Record type
CUSTOMRECORD_NS_SC_EXT_SN_SUBSCRIPTION — Stock Notifications Subscription (241)
Owner
Eduardo Souto (1548)
Consumer emails outside the entity model. If subscribers are not also customer records, they are invisible to GDPR data-subject-access and erasure workflows that only sweep native entities.
MediumCUSTRECORD_CCT_NS_MCICCT_PRIMARYEMAIL / _PHONENUMBERids 2404 · 2402● 2 of 2 populated
Label · Type
“Primary Email / Phone” · Email Address · Phone Number
Record type
CUSTOMRECORD_CCT_NETSUITE_MAPCONTACTCCT — CCT Map & Contact Info (393)
Owner
Sebastian Flaquer (1550)
Holds the company's own published storefront contact info — low practical risk, flagged by pattern for completeness.
MediumCUSTSCRIPT_NS_SC_GTM_CLIENT_IDid 2270○ script parameter
Label · Type
“Google OAuth Client ID” · Free-Form Text, stored
Record type
Script parameter (SCRIPT field)
Owner
Sebastian Flaquer (1550)
OAuth client ids are semi-public identifiers, not secrets. Listed for completeness; downgrade candidate.
LowCUSTENTITY_VAT_REG_NOid 264○ unverifiable · dormant
Label · Type
“VAT Registration No” · Free-Form Text, stored
Record type
Entity field — not applied to customer or vendor
Owner
System / bundle (−5)
Defined in metadata but not exposed on any entity table this role can query. Assumed to be an inactive bundle remnant — deletion candidate if its bundle is retired.
LowCUSTRECORD_ESL_CUST_VAT_REGNO / CUSTRECORD_ESL_SUBMITTER_VATNOids 92 · 77○ 0 rows
Label · Type
“Customer / Submitter VAT Reg No.” · Free-Form Text
Record type
CUSTOMRECORD_ECSL_AUDIT_TRAIL_DTL (19) · _HDR (17)
Owner
System / bundle (−5)
LowCUSTRECORD_ACCT_BANK_ACCOUNT_NUMBERid 406○ 0 of 244 accounts
Label · Type
“Bank Account Number” · Free-Form Text, stored
Record type
Account (type −112)
Owner
System / bundle (−5)
LowCUSTBODY_NS_POS_SIGNATURE_IMAGE · CUSTRECORD_NS_POS_PM_CC_PATTERNids 1161 · 1107○ 0 populated
Label · Type
“Credit Card Signature” (Image) · “Credit Card Pattern” (text)
Record type
Transaction body · CUSTOMRECORD_NS_POS_PAYMENT_METHOD (199)
Owner
Eduardo Souto (1548)
The “pattern” field is BIN-matching regex configuration, not cardholder data — flagged by pattern, cleared on inspection. Signature field unused (0 transactions).

Cleared  Excluded as false positives

≈146 raw hits were dismissed on review: “Author” / “Authorization” / “Authorized Roles” fields (blog authorship and POS approval-role selectors caught by %AUTH%) · “activation” and manufacturing “routing” collisions · email template-text fields (button labels, validation messages) holding no personal data · product-review rating fields caught by an over-broad substring.

04

Population analysis

Fill rate of each hazard field — populated rows over total rows on the host record type. Blue marks fields requiring action. Hover any bar for detail.

Filing Authorization · Credentials
2 of 2 records populated · 100%
Plaintext client id + secret · HIGH
2 / 2
Gateway · Additional Credential ID
15 of 15 records populated · 100%
Classification pending · HIGH
15 / 15
Stock Notifications · Email
3 of 3 records populated · 100%
Consumer PII outside entity model · MEDIUM
3 / 3
Map & Contact · Email / Phone
2 of 2 populated · own published contact info
Low practical risk
2 / 2
PayU · API Key
Host table has 0 rows
Dormant — restrict before use
0
AsiaPay · Hash Secrets (×2)
Both host tables have 0 rows
Dormant — restrict before use
0
Account · Bank Account Number
0 of 244 accounts populated
0 / 244
Transaction · CC Signature Image
0 transactions carry a signature image
0
Payment Method · CC Pattern
0 of 4 records · BIN regex config, not card data
0 / 4
Action required Monitored / dormant

Every credential-pattern field whose host record type is populated is populated at 100% — these fields are in active use, not residue. Empty bars are dormant definitions: cheap to remediate now, before data arrives.

05

Methodology & queries

Read-only SuiteQL against the customfield metadata table, verified with COUNT() aggregates only. Every query is reproducible — use the copy button on each block.

01

Pattern match on metadata. Field names and scriptids matched against two hazard dictionaries — credential terms (password, secret, token, API key, credential, auth, private key) and regulated-data terms (email, phone, SSN, tax id, EIN/TIN, VAT, credit card, CVV, bank account, routing, IBAN, date of birth). Field value types “Email Address” and “Phone Number” matched directly.

02

False-positive triage. Each raw hit reviewed in context — “Author” ≠ “Auth”, “Activation” ≠ “VAT”, “Routing Rule” ≠ bank routing — and template-text fields excluded. 159 raw hits → 13 verified.

03

Population verification. Survivors checked with count-only queries against host tables. Owners resolved via employee; record types via customrecordtype. No stored values read into the report.

Q1Credential-pattern scan of custom field metadata18 hits → 6 kept
SELECT id, scriptid, name, description, fieldtype, fieldvaluetype,
       recordtype, isstored, owner, lastmodifieddate
FROM customfield
WHERE UPPER(name) LIKE '%PASSWORD%' OR UPPER(scriptid) LIKE '%PASSWORD%'
   OR UPPER(scriptid) LIKE '%PASSWD%' OR UPPER(scriptid) LIKE '%PWD%'
   OR UPPER(name) LIKE '%SECRET%'    OR UPPER(scriptid) LIKE '%SECRET%'
   OR UPPER(name) LIKE '%TOKEN%'     OR UPPER(scriptid) LIKE '%TOKEN%'
   OR UPPER(name) LIKE '%API KEY%'   OR UPPER(name) LIKE '%APIKEY%'
   OR UPPER(scriptid) LIKE '%APIKEY%' OR UPPER(scriptid) LIKE '%API_KEY%'
   OR UPPER(name) LIKE '%CREDENTIAL%' OR UPPER(scriptid) LIKE '%CREDENTIAL%'
   OR UPPER(name) LIKE '%AUTH%'      OR UPPER(scriptid) LIKE '%AUTH%'
   OR UPPER(name) LIKE '%PRIVATE KEY%' OR UPPER(scriptid) LIKE '%PRIVKEY%'
ORDER BY fieldtype, scriptid

12 of the 18 raw hits were Author / Authorization false positives dismissed on review.

Q2Regulated-data pattern scan (refined)13 hits
SELECT id, scriptid, name, fieldtype, fieldvaluetype, recordtype, isstored, owner
FROM customfield
WHERE fieldvaluetype IN ('Email Address', 'Phone Number')
   OR UPPER(name) LIKE '%SSN%' OR UPPER(name) LIKE '%SOCIAL SECURITY%'
   OR UPPER(name) LIKE '%TAX ID%' OR UPPER(scriptid) LIKE '%TAXID%'
   OR UPPER(name) LIKE '%BANK ACCOUNT%' OR UPPER(name) LIKE '%ROUTING%'
   OR UPPER(name) LIKE '%IBAN%'
   OR UPPER(name) LIKE '%CREDIT CARD%' OR UPPER(name) LIKE '%CVV%'
   OR UPPER(name) LIKE '%BIRTH%' OR UPPER(scriptid) LIKE '%_DOB%'
   OR UPPER(name) LIKE '%VAT REG%' OR UPPER(scriptid) LIKE '%VAT_REG%'
   OR UPPER(scriptid) LIKE '%VATNO%'
   OR (UPPER(name) LIKE '%EMAIL%' AND fieldtype IN ('ENTITY','BODY','COLUMN'))
   OR (UPPER(name) LIKE '%PHONE%' AND fieldtype IN ('ENTITY','BODY','COLUMN'))
ORDER BY fieldtype, scriptid

A first, broader pass (141 hits) was discarded after bare %VAT% and %MOBILE% patterns matched “activation” and device-layout fields. This refined version returned 13.

Q3Owner and record-type resolution
SELECT id, entityid, firstname, lastname, email
FROM employee WHERE id IN (1548, 1550, 1576);

SELECT internalid, scriptid, name
FROM customrecordtype
WHERE internalid IN (17, 19, 33, 160, 191, 199, 218, 241, 393,
                     504, 506, 507, 510);

Owner −5 denotes a system / bundle installation account.

Q4Population verification — counts only, no values
-- Host-table row counts
SELECT 'CCP_ASIAPAY_CONFIG_REC' AS tbl, COUNT(*) FROM customrecord_ccp_asiapay_config_rec
UNION ALL SELECT 'CCP_ASIAPAY_DIRECT_CONFIG', COUNT(*) FROM customrecord_ccp_asiapay_direct_config
UNION ALL SELECT 'CCP_GATEWAY_ADD_CRED', COUNT(*) FROM customrecord_ccp_gateway_add_cred
UNION ALL SELECT 'FILING_AUTHORIZATION', COUNT(*) FROM customrecord_filing_authorization
UNION ALL SELECT 'EF_BS_SUSCRIPTION', COUNT(*) FROM customrecord_ef_bs_suscription
UNION ALL SELECT 'NS_SC_EXT_SN_SUBSCRIPTION', COUNT(*) FROM customrecord_ns_sc_ext_sn_subscription
UNION ALL SELECT 'NS_POS_PAYMENT_METHOD', COUNT(*) FROM customrecord_ns_pos_payment_method
UNION ALL SELECT 'CCT_NETSUITE_MAPCONTACTCCT', COUNT(*) FROM customrecord_cct_netsuite_mapcontactcct
UNION ALL SELECT 'ECSL_AUDIT_TRAIL_HDR', COUNT(*) FROM customrecord_ecsl_audit_trail_hdr
UNION ALL SELECT 'ECSL_AUDIT_TRAIL_DTL', COUNT(*) FROM customrecord_ecsl_audit_trail_dtl;

-- Field-level fill rates (COUNT(col) counts non-null only)
SELECT COUNT(custrecord_ccp_gateway_cred_id), COUNT(*) FROM customrecord_ccp_gateway_add_cred;
SELECT COUNT(custrecord_ns_pos_pm_cc_pattern), COUNT(*) FROM customrecord_ns_pos_payment_method;
SELECT COUNT(custrecord_ns_sc_ext_sn_s_email), COUNT(*) FROM customrecord_ns_sc_ext_sn_subscription;
SELECT COUNT(custrecord_cct_ns_mcicct_phonenumber), COUNT(*) FROM customrecord_cct_netsuite_mapcontactcct;
SELECT COUNT(custrecord_cct_ns_mcicct_primaryemail), COUNT(*) FROM customrecord_cct_netsuite_mapcontactcct;
SELECT COUNT(custrecord_acct_bank_account_number), COUNT(*) FROM account;
SELECT COUNT(custbody_ns_pos_signature_image) FROM transaction;

custrecord_filing_authorization_cred is not exposed as a SuiteQL column; its population (2 of 2) was confirmed via record-schema introspection instead.

Q5Coverage denominator
SELECT COUNT(*) AS total_fields,
       SUM(CASE WHEN isstored = 'T' THEN 1 ELSE 0 END) AS stored_fields
FROM customfield;
-- 2,485 total · 2,406 stored
06

Assumptions & limitations

Read before acting

• Name-based detection only. A field named innocuously (e.g., “Config Value”) that actually stores a secret will not be caught. Free-text fields, long-text blobs, and file-cabinet contents were not content-scanned.

• Populated ≠ sensitive. “Additional Credential ID” (15/15) may hold reference identifiers rather than secrets — values were deliberately not read. Manual review of one record is recommended.

• CUSTENTITY_VAT_REG_NO could not be population-checked — not applied to customer or vendor record types, not exposed to SuiteQL. Assumed dormant.

• Owner attribution reflects the field's owner attribute; for bundle-installed fields this is the installing user or system account (−5), not necessarily the current maintainer.

• Scope is custom field definitions. Native fields, saved-search exposure, deployment-level script parameters, and workflow custom fields were out of scope for this pass.

• The scan ran under role id 3 on 2026-09-04; fields hidden from this role by field-level security would not appear.

07

Remediation roadmap

Six steps, ordered by urgency. Click a task to mark it complete — progress is saved in this browser and shown in the sidebar. (Checkmarks are a local working aid; they do not change anything in NetSuite.)

0 of 6 complete
Immediate
Rotate the Online Filing Authorization secret

The client id + secret in custrecord_filing_authorization_cred surfaced in plaintext during this scan and is visible to any role with view access to record type 160. Rotate at the issuing provider first, then remediate storage.

This week
Migrate stored secrets to NetSuite Secrets Management

Replace plain custom fields with API Secrets (Setup > Company > API Secrets) referenced via secure strings in script. Blank the legacy field values after migration.

This week
Classify the 15 “Additional Credential ID” values

Open one customrecord_ccp_gateway_add_cred record: if the field holds gateway secrets, apply the previous step; if reference ids, downgrade and close the finding.

This month
Restrict payment-gateway config record types

Lock CUSTOMRECORD_CCP_PAYU_CONFIG_REC, both AsiaPay config types, and CUSTOMRECORD_CCP_GATEWAY_ADD_CRED to administrator-only record permissions before they are populated.

This month
Fold subscription emails into privacy workflows

Ensure CUSTOMRECORD_NS_SC_EXT_SN_SUBSCRIPTION is included in data-subject-access and erasure procedures, or link subscribers to entity records.

Quarterly
Re-run this scan and prune dormant hazards

Queries Q1–Q2 are reusable as-is. Consider deleting unused bundle fields (CUSTENTITY_VAT_REG_NO, bank-account and signature fields) if their bundles are retired — an empty hazard field is still an invitation.

Disclaimer. This report was generated by an automated, pattern-based scan executed on September 4, 2026 under the requesting user's NetSuite role. It is a point-in-time configuration review, not a comprehensive penetration test or a guarantee of compliance with GDPR, PCI-DSS, or any other regulation. No stored field values are reproduced in this document; population figures are non-null row counts only. Findings should be validated by the data owner before remediation. Source: SuiteQL queries against customfield, customrecordtype, employee, and host record tables in account TD3096877.

Chartstone · Sensitive-Data Hazard Scan · September 2026