
instance-security
by groeimetai
🤖 AI-powered ServiceNow development with 400+ MCP tools. Works with Claude, GPT, Gemini, Ollama & 75+ providers. Deploy widgets, manage incidents, automate workflows - all through natural language. Open-source Build Agent alternative.
SKILL.md
name: instance-security description: This skill should be used when the user asks to "instance security", "hardening", "security best practices", "authentication", "SSO", "MFA", "session", "XSS", "injection", or any ServiceNow Instance Security development. license: Apache-2.0 compatibility: Designed for Snow-Code and ServiceNow development metadata: author: groeimetai version: "1.0.0" category: servicenow tools:
- snow_property_get
- snow_property_set
- snow_execute_script_with_output
- snow_review_access_control
- snow_query_table
Instance Security for ServiceNow
Instance Security covers authentication, authorization, and security hardening.
Security Layers
Network Security
↓
Authentication (SSO, MFA)
↓
Session Management
↓
Authorization (ACLs, Roles)
↓
Data Protection
↓
Audit & Logging
Key Tables
| Table | Purpose |
|---|---|
sys_user | User accounts |
sys_user_role | Roles |
sys_security_acl | Access controls |
sysevent_log | Security events |
sys_properties | Security settings |
Authentication Security (ES5)
Password Policy Configuration
// Check password strength (ES5 ONLY!)
function validatePasswordStrength(password) {
var issues = [];
// Minimum length
var minLength = parseInt(gs.getProperty('glide.security.password.min_length', '8'), 10);
if (password.length < minLength) {
issues.push('Password must be at least ' + minLength + ' characters');
}
// Complexity requirements
if (!/[A-Z]/.test(password)) {
issues.push('Password must contain uppercase letter');
}
if (!/[a-z]/.test(password)) {
issues.push('Password must contain lowercase letter');
}
if (!/[0-9]/.test(password)) {
issues.push('Password must contain number');
}
if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
issues.push('Password must contain special character');
}
return {
valid: issues.length === 0,
issues: issues
};
}
Session Security
// Check session validity (ES5 ONLY!)
function isSessionSecure() {
var session = gs.getSession();
// Check session age
var maxAge = parseInt(gs.getProperty('glide.security.session.timeout', '60'), 10);
var sessionAge = session.getSessionAge() / 60000; // Convert to minutes
if (sessionAge > maxAge) {
return { valid: false, reason: 'Session expired' };
}
// Check for session fixation
var clientIP = gs.getSession().getClientIP();
var originalIP = session.getValue('original_ip');
if (originalIP && clientIP !== originalIP) {
return { valid: false, reason: 'IP address changed' };
}
return { valid: true };
}
// Force re-authentication
function requireReauthentication(reason) {
gs.getSession().invalidate();
gs.addErrorMessage(reason);
// Redirect to login
response.sendRedirect('/login.do');
}
MFA Implementation (ES5)
Check MFA Status
// Check if user has MFA enabled (ES5 ONLY!)
function hasMFAEnabled(userSysId) {
var user = new GlideRecord('sys_user');
if (!user.get(userSysId)) {
return false;
}
// Check MFA settings
var mfa = new GlideRecord('sys_user_mfa');
mfa.addQuery('user', userSysId);
mfa.addQuery('active', true);
mfa.query();
return mfa.hasNext();
}
// Enforce MFA for sensitive operations
function requireMFA(operation) {
var userId = gs.getUserID();
if (!hasMFAEnabled(userId)) {
gs.addErrorMessage('MFA required for ' + operation);
return false;
}
// Check if MFA verified this session
var session = gs.getSession();
var mfaVerified = session.getValue('mfa_verified');
if (mfaVerified !== 'true') {
// Trigger MFA challenge
gs.eventQueue('user.mfa.challenge', null, userId, operation);
return false;
}
return true;
}
Input Validation (ES5)
XSS Prevention
// Sanitize user input (ES5 ONLY!)
function sanitizeInput(input) {
if (!input) return '';
// Encode HTML entities
var sanitized = input.toString()
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
return sanitized;
}
// Validate and sanitize before storage
function validateUserInput(tableName, fieldName, value) {
// Check field type
var dict = new GlideRecord('sys_dictionary');
dict.addQuery('name', tableName);
dict.addQuery('element', fieldName);
dict.query();
if (!dict.next()) {
return { valid: false, error: 'Field not found' };
}
var fieldType = dict.getValue('internal_type');
// Validate based on type
if (fieldType === 'string' || fieldType === 'html') {
// Check for script injection
if (/<script/i.test(value)) {
return { valid: false, error: 'Script tags not allowed' };
}
// Check for event handlers
if (/on\w+\s*=/i.test(value)) {
return { valid: false, error: 'Event handlers not allowed' };
}
}
return { valid: true, sanitized: sanitizeInput(value) };
}
SQL Injection Prevention
// Safe query building (ES5 ONLY!)
// NEVER concatenate user input directly into queries
// BAD - Vulnerable to injection
// gr.addEncodedQuery('name=' + userInput);
// GOOD - Use parameterized queries
function safeQuery(tableName, fieldName, value) {
var gr = new GlideRecord(tableName);
// GlideRecord methods handle escaping
gr.addQuery(fieldName, value);
gr.query();
return gr;
}
// For encoded queries, validate input
function safeEncodedQuery(tableName, userQuery) {
// Whitelist allowed fields
var allowedFields = ['number', 'short_description', 'state', 'priority'];
// Parse and validate query
var parts = userQuery.split('^');
var safeQuery = [];
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
var match = part.match(/^(\w+)(=|!=|LIKE|CONTAINS)(.+)$/);
if (match) {
var field = match[1];
if (allowedFields.indexOf(field) !== -1) {
safeQuery.push(part);
}
}
}
var gr = new GlideRecord(tableName);
if (safeQuery.length > 0) {
gr.addEncodedQuery(safeQuery.join('^'));
}
gr.query();
return gr;
}
Security Properties (ES5)
Key Security Settings
// Get security-related properties (ES5 ONLY!)
function getSecuritySettings() {
return {
// Session settings
session_timeout: gs.getProperty('glide.security.session.timeout'),
session_cookie_secure: gs.getProperty('glide.security.session.cookie.secure'),
// Password settings
password_min_length: gs.getProperty('glide.security.password.min_length'),
password_history: gs.getProperty('glide.security.password.history'),
password_expiry: gs.getProperty('glide.security.password.expiry'),
// Login settings
max_failed_logins: gs.getProperty('glide.security.password.max_failed_logins'),
lockout_duration: gs.getProperty('glide.security.password.lockout_duration'),
// General security
csrf_protection: gs.getProperty('glide.security.csrf.strict_validation'),
xss_protection: gs.getProperty('glide.security.xss.strict')
};
}
// Update security property
function setSecurityProperty(name, value, requireRestart) {
gs.setProperty(name, value);
if (requireRestart) {
gs.warn('Security property changed: ' + name + '. Restart may be required.');
}
// Log security change
gs.eventQueue('security.property.changed', null, name, value);
}
Security Auditing (ES5)
Log Security Events
// Log security event (ES5 ONLY!)
function logSecurityEvent(eventType, details) {
var log = new GlideRecord('syslog');
log.initialize();
log.setValue('level', 'warning');
log.setValue('source', 'Security');
log.setValue('message', eventType + ': ' + JSON.stringify(details));
log.insert();
// Also queue for security monitoring
gs.eventQueue('security.event', null, eventType, JSON.stringify(details));
}
// Track failed login attempts
function trackFailedLogin(username, ipAddress) {
logSecurityEvent('failed_login', {
username: username,
ip: ipAddress,
timestamp: new GlideDateTime().getDisplayValue()
});
// Check for brute force
var recentFailures = countRecentFailures(username, 5); // Last 5 minutes
var maxFailures = parseInt(gs.getProperty('glide.security.password.max_failed_logins', '5'), 10);
if (recentFailures >= maxFailures) {
lockAccount(username);
logSecurityEvent('account_locked', {
username: username,
reason: 'Too many failed login attempts',
failures: recentFailures
});
}
}
Security Health Check
// Check instance security health (ES5 ONLY!)
function securityHealthCheck() {
var issues = [];
// Check for default admin password
var admin = new GlideRecord('sys_user');
if (admin.get('user_name', 'admin')) {
if (admin.getValue('password') === gs.getProperty('glide.security.default.admin.password')) {
issues.push({ severity: 'critical', issue: 'Default admin password not changed' });
}
}
// Check session timeout
var timeout = parseInt(gs.getProperty('glide.security.session.timeout', '0'), 10);
if (timeout === 0 || timeout > 60) {
issues.push({ severity: 'high', issue: 'Session timeout too long or disabled' });
}
// Check password policy
var minLength = parseInt(gs.getProperty('glide.security.password.min_length', '0'), 10);
if (minLength < 12) {
issues.push({ severity: 'medium', issue: 'Password minimum length less than 12' });
}
// Check HTTPS enforcement
if (gs.getProperty('glide.security.session.cookie.secure') !== 'true') {
issues.push({ severity: 'high', issue: 'Secure cookies not enforced' });
}
return {
healthy: issues.length === 0,
issues: issues
};
}
MCP Tool Integration
Available Tools
| Tool | Purpose |
|---|---|
snow_property_get | Check security properties |
snow_execute_script_with_output | Test security scripts |
snow_review_access_control | Review ACLs |
Example Workflow
// 1. Check security properties
await snow_property_get({
name: 'glide.security.session.timeout'
});
// 2. Run security health check
await snow_execute_script_with_output({
script: `
var health = securityHealthCheck();
gs.info(JSON.stringify(health));
`
});
// 3. Review access controls
await snow_query_table({
table: 'sys_security_acl',
query: 'active=true^admin_overrides=true',
fields: 'name,operation,type,script'
});
Best Practices
- Strong Passwords - Enforce complexity
- MFA - Enable for privileged users
- Session Timeout - 15-30 minutes
- Input Validation - Sanitize everything
- Least Privilege - Minimal roles
- Audit Logging - Log security events
- Regular Reviews - Security assessments
- ES5 Only - No modern JavaScript syntax
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
1ヶ月以内に更新
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon


