In Part 1 of this series, we identified the problem as well as a weak solution. In this part, we will explain why the solution from Part 1 is weak and provide a better solution. If you missed Part 1, we highly recommend that you review it first; otherwise, it might be difficult to follow this article.
TL;DR
- NetSuite features an alternative journal entry import path which is, surprisingly, not controlled by the CSV import permission. As such, simply removing the ability to import CSVs does not suffice to block the JE loophole.
- The global CSV settings need to be updated to produce a rock-solid solution to the JE backdoor.
Challenge (Recap)
Here’s a quick recap of how we got here: During the annual audit meeting at Asoville Inc., auditor Alexa pointed out a segregation of duties (SoD) violation resulting from the following configuration:
- The role that executes the Period Close Checklist requires the “Create” or higher access for the
Transactions >> Make Journal Entry
. Without this permission, the “Eliminate Intercompany Transactions” step of the period checklist will fail. - However, this role also has the permission to approve journal entries. This leads to an SoD violation as a role that is able to create a transaction should not be able to approve it.
To address this situation, Edet, our capable (but not imperfect) NetSuite Admin, implemented a solution that she thought was sufficient to address the problem:
- She created a workflow to detect and block any JE creation attempt from the role on which the SoD had been flagged.
- Additionally, she removed the permission Setup >> Import CSV File from the role.
Effectively, this would prevent anyone logged into the “ASO Controller” role from creating JEs via the UI or via CSV import, while allowing the system to execute the Period Checklist successfully. At least, that’s what she thought…
Journal Entry Import Backdoor
The problem with Edet’s solution is that NetSuite supports importing Journal Entries via an alternative path that is NOT covered by the CSV import permission. Specifically, it is still possible to import JEs via Transactions >> Financial >> Make Journal Entries
or Transactions >> Financial >> Make Advanced Intercompany Journal Entries
as illustrated here (1:45).
Contrary to expectations, these paths are not covered by the CSV import permission! My guess is that the Transactions >> Financial...
import paths preceded the more robust import tool (accessible via Setup >> Import/Export
). And, when the latter was built, the permission Setup >> Import CSV File
was defined but not applied to the former paths. In any case, this is a potentially serious issue. Gladly, there is a way to block it as I’ll explain shortly.
Journal Entry Import Backdoor Fix
The solution turns out to be pretty straightforward. Setup >> Import/Export >> CSV Import Preferences contains global preferences related to CSV imports one of which is “Run Server SuiteScript and Trigger Workflows”. By enabling that preference, we instruct NetSuite to always trigger server-side script and workflows with CSV import scope. After turning on this preference, our backdoor JE imports now trigger the workflow we built in Part 1 and fail as expected; see the following demonstration (1:27).
A Note About the Global “Run Server SuiteScript and Trigger Workflows” CSV Import Preference
After turning on the global “Run Server SuiteScript and Trigger Workflows” option, the corresponding option on individual CSV import template becomes grayed out for non-admin users as illustrated above. This makes sense as the global setting should take precedence. However, it is important to bear the following in mind:
- The setting does not apply to existing CSV import templates: Any CSV import templates before the global parameter was set will still bypass server-side script and workflows if that option was unchecked when the template was initially created. If you want to enforce the global preference, you’ll need to delete such templates and recreate them.
- There are scenarios where you might want to override the global preference e.g. when performing large (historical) imports that are unrelated to the control in question. To address this, you have two options:
- Create/edit the CSV import template from the Admin role. The option will not be grayed out and can be turned off. The change will also be persistent for other users i.e. if the Admin turns off the preference on a particular saved CSV import template, other users accessing that template will also see the preference as unchecked and will be unable to toggle it because it is grayed out.
- Grant the roles in question the permission
Setup >> Control SuiteScript and Workflow Trigger per CSV Import
. This will allow them overrule the global preference on individual CSV import templates.[I]NetSuite (March 4, 2021). Setting CSV Import Preferences. Available at: https://netsuite.custhelp.com/app/answers/detail/a_id/9941. [Accessed: September, 29, 2021]
This global “Run Server SuiteScript and Trigger Workflows” CSV Import Preference is really very handy and provides more granular control for CSV import. And, of course, it enables us to address the import backdoor and produce a rock-solid control.
The Complete Solution
Let’s put all the pieces together. To properly address the JE import backdoor, you need to do the following:
- Implement and deploy a workflow (or script) that prevents creation of journal entries from the role(s) in question via the UI or CSV import. A sample implementation of such a workflow was provided in Part 1 of this series. There is no strong reason to take scripting route (unless you’re unfortunately one of those “avoid-workflows-at-all-costs-even-when-it-makes-sense” NetSuite developers – let’s have a chat about that some other time, shall we?)
- Turn on the global option “Run Server SuiteScript and Trigger Workflows” via
Setup >> Import/Export >> CSV Import Preferences
. - Make sure that the role(s) in question do not have the permission
Setup >> Control SuiteScript and Workflow Trigger per CSV Import
. Otherwise, they’ll be able to overrule the global preference at individual import level. Note though that this will not affect the control as the backdoor JE import route is only affected by the global setting. - Optionally, recreate any existing saved CSV import templates of interest where the corresponding import-level option is turned off.
- Test the control. Also confirm that the Period Close Checklist executes successfully i.e. that your control is not too aggressive and thus, interferes with system-triggered processes/contexts.
Back at Asoville Inc, Edet is relieved. One more problem solved and good insights gained. Alexa, the auditor, is also satisfied with this solution (which, by the way, the already knew about).
We hope that you too have found this series insightful and that, unlike Edet, you’ll be ahead of your auditors. If you’re an auditor, well, you know have one more secret weapon to smash your next NetSuite audit. Good luck!
NetSuite Insights is on a mission to raise the standards around NetSuite practices, one insight at a time. If that resonates with you, check out how you can become an author/collaborator here.
Also, consider subscribing to our no-nonsense email list to get these insights delivered to your inbox as soon as they’re published. Sometimes, ignorance is a choice. Choose wisely!
Related Posts
Further Reading