Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Script Include: QuarantineAttachmentUtils
// Purpose: Utilities for quarantining attachments.
// Scope: global or scoped. Client callable false.

var QuarantineAttachmentUtils = Class.create();
QuarantineAttachmentUtils.prototype = {
initialize: function() {},

ensureQuarantineRecord: function(table, fileName, reason, groupSysId) {
var gr = new GlideRecord(table);
gr.initialize();
if (gr.isValidField('short_description'))
gr.short_description = 'Quarantined attachment: ' + fileName;
if (gr.isValidField('description'))
gr.description = 'Reason: ' + reason;
if (groupSysId && gr.isValidField('assignment_group'))
gr.assignment_group = groupSysId;
return gr.insert();
},

copyAndDelete: function(fromTable, fromSysId, toTable, toSysId, attachSysId) {
var gsa = new GlideSysAttachment();
gsa.copy(fromTable, fromSysId, toTable, toSysId, attachSysId);
gsa.deleteAttachment(attachSysId);
},

getExt: function(fileName) {
var m = String(fileName || '').match(/\.([A-Za-z0-9]+)$/);
return m ? m[1].toLowerCase() : '';
},

type: 'QuarantineAttachmentUtils'
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Quarantine risky attachments by type or size

## What this solves
Users sometimes upload executables or very large files via email or forms. This rule quarantines risky attachments by copying them off the original record, deleting the original, and keeping an audit trail.

## Where to use
- Table: `sys_attachment`
- When: before insert
- Order: early (for example 50)

## How it works
- Checks file extension and size against configurable thresholds
- Creates or reuses a quarantine record (table `x_quarantine_attachment` or default `incident` as a safe example)
- Copies the new attachment to the quarantine record via `GlideSysAttachment.copy`
- Deletes the original attachment via `GlideSysAttachment.deleteAttachment`
- Logs what happened with minimal, readable messages

## Configure
In the Business Rule:
- `BLOCKED_EXTS`: extensions to quarantine
- `MAX_SIZE_MB`: size threshold
- `QUARANTINE_TABLE`: table to hold quarantined items
- `ASSIGNMENT_GROUP_SYSID`: optional group to triage quarantines

## References
- GlideSysAttachment API
https://www.servicenow.com/docs/bundle/zurich-api-reference/page/app-store/dev_portal/API_reference/GlideSysAttachment/concept/c_GlideSysAttachmentAPI.html
- Business Rules
https://www.servicenow.com/docs/bundle/zurich-application-development/page/build/applications/concept/c_BusinessRules.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Business Rule: Quarantine risky attachments by type or size
// Table: sys_attachment | When: before insert

(function executeRule(current, previous /*null*/) {
try {
// Config
var BLOCKED_EXTS = ['exe', 'bat', 'cmd', 'ps1', 'js'];
var MAX_SIZE_MB = 25; // quarantine files larger than this
var QUARANTINE_TABLE = 'incident'; // replace with your quarantine table if available
var ASSIGNMENT_GROUP_SYSID = ''; // optional triage group

// Skip non-file or missing metadata
if (!current.table_name || !current.file_name) return;

var utils = new QuarantineAttachmentUtils();
var ext = utils.getExt(current.file_name);
var sizeBytes = Number(current.size_bytes || 0);
var isBlocked = BLOCKED_EXTS.indexOf(ext) !== -1;
var isTooLarge = sizeBytes > (MAX_SIZE_MB * 1024 * 1024);

if (!(isBlocked || isTooLarge)) return;

var reason = isBlocked ? ('blocked extension .' + ext) : ('size ' + sizeBytes + ' bytes exceeds ' + MAX_SIZE_MB + ' MB');

// Create quarantine record
var quarantineId = utils.ensureQuarantineRecord(QUARANTINE_TABLE, current.file_name, reason, ASSIGNMENT_GROUP_SYSID);

// Copy attachment to quarantine and delete original
utils.copyAndDelete(current.table_name, current.table_sys_id, QUARANTINE_TABLE, quarantineId, current.sys_id);

gs.info('[ATTACHMENT-QUARANTINE] file=' + current.file_name +
' ext=' + ext +
' size=' + sizeBytes +
' reason=' + reason +
' quarantined_to=' + QUARANTINE_TABLE + ':' + quarantineId);
} catch (e) {
gs.error('Attachment quarantine failed: ' + e.message);
}
})(current, previous);
Loading