DEV Community

Jason Shouldice
Jason Shouldice

Posted on • Edited on • Originally published at vicistack.com

Your VICIdial Server Is Probably Already Compromised (Here's How to Check)

I've audited over 100 VICIdial deployments. The majority had at least one critical vulnerability that was actively being scanned for by automated exploit kits. A good chunk of them had already been compromised — they just didn't know it yet.

The damage always looks the same: toll fraud charges on a Monday morning ($14,000 in international calls over a weekend is a common number), or lead data floating around a Telegram channel, or a defaced admin panel. And the root cause is almost always the same too: internet-exposed web interface, default credentials, and code that hasn't been updated since install day.

Here's how to check if you're exposed and what to fix first.

Check Your SVN Revision Right Now

The most critical thing first. In September 2024, two CVEs were disclosed that together allow unauthenticated remote code execution on VICIdial:

  • CVE-2024-8503 — SQL injection in /vicidial/user_stats.php. A single crafted HTTP request dumps your entire user table, including passwords. Automated exploit tools were published within days.
  • CVE-2024-8504 — Authenticated RCE. Once an attacker has admin creds from the SQL injection above, they can inject arbitrary OS commands through the admin interface.

Chained together, these two CVEs give an unauthenticated attacker full root access. Dozens of installations were popped over a single weekend after disclosure.

cd /usr/share/astguiclient
svn info | grep "Revision"
Enter fullscreen mode Exit fullscreen mode

If your revision is below 3848, you're vulnerable. Run svn update immediately. If you can't update right now, block public access to every PHP endpoint in the vicidial directory — that's the attack surface.

There are also older CVEs still in active exploitation. CVE-2021-28854 (unauthenticated command injection) and CVE-2013-4467/4468 (SQL injection and command injection from over a decade ago). We still find these in production during audits in 2025 because someone installed VICIdial from a 2012 ISO, never updated it, and it's been dialing ever since.

The pattern is clear: every major VICIdial CVE follows the same template — unauthenticated access to a web-facing PHP script that accepts unsanitized input. The attack surface is the web layer.

The Five-Minute Compromise Check

Already worried you've been hit? Run these:

# Unknown cron jobs — check ALL users
for user in $(cut -d: -f1 /etc/passwd); do
    crontab -u $user -l 2>/dev/null | grep -v "^#" | grep -v "^$" && echo "^^^ $user ^^^"
done

# Unexpected processes on network ports
ss -tlnp | grep -v -E "asterisk|httpd|mysqld|sshd|perl"

# Modified PHP files (compare against SVN)
cd /usr/share/astguiclient && svn status | grep "^M"

# Unknown MySQL users
mysql -e "SELECT user, host FROM mysql.user" 2>/dev/null
Enter fullscreen mode Exit fullscreen mode

If you see cron jobs you didn't add, processes listening on ports you don't recognize, or MySQL users you never created — you've been compromised. The most reliable canary is your carrier bill: a sudden spike in international call volume over a weekend is almost always toll fraud from a compromised Asterisk instance. Set up carrier-side spending alerts as a safety net.

Firewall: The Default-Deny Foundation

A properly configured firewall eliminates entire categories of attack. It costs nothing and takes 30 minutes. Yet the majority of VICIdial installations we audit have either no firewall at all, or one so permissive it might as well not exist.

Start from zero. Block everything. Open only what's needed:

# Default deny
firewall-cmd --set-default-zone=drop

# SSH from management IPs only
firewall-cmd --permanent --zone=vicidial --add-rich-rule='rule family="ipv4" source address="YOUR.OFFICE.IP/32" port port="22" protocol="tcp" accept'

# HTTPS for agents
firewall-cmd --permanent --zone=vicidial --add-rich-rule='rule family="ipv4" source address="YOUR.AGENT.SUBNET/24" port port="443" protocol="tcp" accept'

# SIP from carriers ONLY (not the whole internet)
firewall-cmd --permanent --zone=vicidial --add-rich-rule='rule family="ipv4" source address="CARRIER.SIP.IP/32" port port="5060" protocol="udp" accept'

# RTP media from carriers only
firewall-cmd --permanent --zone=vicidial --add-rich-rule='rule family="ipv4" source address="CARRIER.SIP.IP/32" port port="10000-20000" protocol="udp" accept'

firewall-cmd --reload
Enter fullscreen mode Exit fullscreen mode

The most critical rule people forget: Port 5038 (AMI) must be localhost only. The Asterisk Manager Interface grants full control of Asterisk — originating calls, hanging up channels, reading configuration. The default credentials (cron/1234) are documented in every install guide on the internet. If AMI is reachable from the network, an attacker with those credentials can make international calls, wipe voicemail, or crash your PBX. I've seen this exploited more than any other single misconfiguration.

# Verify AMI is bound to localhost
iptables -A INPUT -p tcp --dport 5038 -s 127.0.0.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 5038 -j DROP
Enter fullscreen mode Exit fullscreen mode

Asterisk SIP Security

A misconfigured Asterisk server exposed to the internet will be found and exploited within hours. SIP scanners run 24/7 across the entire IPv4 space, probing port 5060 for open registrations.

Lock down sip.conf:

[general]
allowguest=no          ; Don't accept calls from unregistered endpoints
alwaysauthreject=yes   ; Same error for wrong user vs wrong password (prevents enumeration)
bindaddr=YOUR.SERVER.IP ; Don't bind to 0.0.0.0
srvlookup=no           ; Prevents DNS rebinding attacks
Enter fullscreen mode Exit fullscreen mode

Fail2ban is non-negotiable. Without it, brute-force attacks against your SIP endpoints will eventually succeed.

# /etc/fail2ban/jail.local
[asterisk]
enabled  = true
filter   = asterisk
logpath  = /var/log/asterisk/messages
maxretry = 3
findtime = 600
bantime  = 86400
ignoreip = 127.0.0.1/8 YOUR.OFFICE.IP/32
Enter fullscreen mode Exit fullscreen mode

Set bantime to 86400 (24 hours) minimum. The default 600 seconds is useless — automated scanners just wait 10 minutes and resume. We run 7-day bans on production systems. For repeat offenders, enable bantime.increment = true with exponential durations.

SIP ACLs add a proactive layer on top of fail2ban's reactive one. Configure ACLs in /etc/asterisk/acl.conf to reject connections from unknown IPs before authentication is even attempted:

[carrier-acl]
deny=0.0.0.0/0.0.0.0
permit=CARRIER.PRIMARY.IP/255.255.255.255
permit=CARRIER.SECONDARY.IP/255.255.255.255
Enter fullscreen mode Exit fullscreen mode

Apply the ACL to your trunk definitions. Now even if fail2ban hasn't caught an attacker yet and your firewall has a gap, Asterisk itself rejects the connection at the application layer.

Every SIP endpoint — every phone, every trunk, every agent extension — needs a unique randomly generated password of at least 20 characters. Generate them with openssl rand -base64 24. SIP uses digest auth (MD5-based), which isn't the strongest protocol. Long random passwords compensate.

MySQL Access Control

VICIdial's database contains everything: agent credentials, lead data with names and phone numbers, campaign configurations, API keys. A compromised database is a total compromise.

Bind MySQL to localhost on single-server installs (bind-address = 127.0.0.1 in my.cnf). In a cluster, bind to the private interface only.

Audit your users:

SELECT user, host FROM mysql.user WHERE host = '%';
Enter fullscreen mode Exit fullscreen mode

Any user with host='%' is accessible from anywhere on the network. Fix it:

DROP USER 'cron'@'%';
CREATE USER 'cron'@'192.168.1.%' IDENTIFIED BY 'STRONG_PASSWORD';
GRANT SELECT, INSERT, UPDATE, DELETE ON asterisk.* TO 'cron'@'192.168.1.%';
FLUSH PRIVILEGES;
Enter fullscreen mode Exit fullscreen mode

Create separate users with minimal privileges: a cron user for background processes, a custom user for the web interface, and a reports user with SELECT-only access for reporting. Lock root to localhost only.

VICIdial stores MySQL credentials in /etc/astguiclient.conf and the web directory's dbconnect_mysqli.php. Both files must have restrictive permissions:

chmod 640 /etc/astguiclient.conf
chown root:asterisk /etc/astguiclient.conf
chmod 640 /var/www/html/vicidial/dbconnect_mysqli.php
chown root:apache /var/www/html/vicidial/dbconnect_mysqli.php
Enter fullscreen mode Exit fullscreen mode

AMI Security: The Control Plane Nobody Locks Down

The Asterisk Manager Interface is VICIdial's remote control for Asterisk. Through AMI, you can originate calls, hang up channels, reload configuration, and execute arbitrary commands. VICIdial's Perl scripts communicate with Asterisk exclusively through AMI on port 5038.

The default credentials are cron/1234. They're documented in every install guide on the internet. If AMI is reachable from the network with those credentials, an attacker has full control of your PBX.

; /etc/asterisk/manager.conf
[general]
enabled = yes
port = 5038
bindaddr = 127.0.0.1    ; CRITICAL: localhost only

[cron]
secret = USE_A_GENERATED_32_CHARACTER_PASSWORD_HERE
deny = 0.0.0.0/0.0.0.0
permit = 127.0.0.1/255.255.255.0
Enter fullscreen mode Exit fullscreen mode

After changing the AMI secret, update it in /etc/astguiclient.conf (the VARserver_password field). If these don't match, every VICIdial Perl script fails to connect and your system stops dialing. Test during a maintenance window.

In a cluster, VICIdial scripts on each telephony server communicate with their local Asterisk only via AMI. There's no legitimate reason for AMI traffic between servers. If you see port 5038 open in cluster firewall rules, that's a misconfiguration — remove it.

HTTPS and Admin Panel Lockdown

Running VICIdial over plain HTTP in 2026 is negligent. Agent credentials, lead data with names and phone numbers, and session tokens all traverse the network in cleartext. On any network segment an attacker can sniff, every agent login is compromised.

Use Let's Encrypt with certbot for free automated certificates:

yum install -y certbot python3-certbot-apache
certbot --apache -d dialer.yourdomain.com
certbot renew --dry-run
Enter fullscreen mode Exit fullscreen mode

Force HTTPS and configure modern TLS — disable TLSv1.0 and TLSv1.1, set SSLHonorCipherOrder on, add HSTS headers. If you're running WebRTC/ViciPhone, it requires valid SSL certificates — self-signed certs won't work in modern browsers.

The admin panel should never be accessible from the open internet. Restrict it in Apache:

<Directory "/var/www/html/vicidial">
    <RequireAny>
        Require ip 192.168.1.0/24
        Require ip YOUR.OFFICE.IP/32
    </RequireAny>
</Directory>

<LocationMatch "/(agc|vicidial)/(admin|manager_send|AST_|user_stats|dbconnect)">
    <RequireAny>
        Require ip 192.168.1.0/24
        Require ip YOUR.OFFICE.IP/32
    </RequireAny>
</LocationMatch>
Enter fullscreen mode Exit fullscreen mode

The LocationMatch block is important — it blocks access to specific sensitive scripts even if someone finds a way around the directory restriction. The user_stats.php endpoint is exactly where CVE-2024-8503 lives.

If managers need remote access, the answer is WireGuard. Takes 10 minutes to set up, eliminates the entire class of web application attacks against the admin interface. Remote management without VPN should not exist.

VICIdial has a granular permission system that almost nobody configures properly. Under Admin > User Groups:

  • Level 1 (Agent): Agent screen only. No admin access. 90% of your users should be here.
  • Level 7 (Manager): Reports and campaign management for their group only.
  • Level 8 (Senior Manager): Full campaign and user management within their group.
  • Level 9 (Admin): Full access. Limit to 2-3 people maximum.

Change the default admin credentials immediately. Default 6666/1234 is the first thing any attacker tries. Create a new admin with a strong password, then deactivate (not delete) the defaults.

For API security: create dedicated API users that cannot log into the agent or admin interface, restrict each to specific IPs with api_ip, and create separate users for each integration (CRM, reporting, IVR). Compromising one shouldn't compromise all three.

Web Server and PHP Hardening

Apache exposes more than it should out of the box. Disable directory listing (Options -Indexes), hide the server version (ServerTokens Prod, ServerSignature Off), disable the TRACE method (TraceEnable Off), and block access to /server-info and /server-status from external IPs.

PHP hardening for production VICIdial:

; /etc/php.ini
expose_php = Off
display_errors = Off
log_errors = On
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_strict_mode = 1
Enter fullscreen mode Exit fullscreen mode

Consider disable_functions = exec,passthru,shell_exec,system,proc_open,popen but test thoroughly — some VICIdial admin functions use exec() for system operations. If specific admin features break, selectively re-enable exec only and compensate with stricter filesystem permissions.

Install mod_evasive for basic rate limiting against brute-force login attacks:

DOSPageCount 5
DOSSiteCount 50
DOSBlockingPeriod 300
Enter fullscreen mode Exit fullscreen mode

This blocks any IP hitting the same page more than 5 times per second. Legitimate agent usage never triggers these thresholds.

Recording Access Control

Call recordings are regulated data. PCI-DSS, HIPAA, GDPR, and state privacy laws all have specific requirements. A VICIdial installation with world-readable recordings on an unprotected HTTP path is a compliance violation waiting to become a lawsuit.

Block direct HTTP access to recording directories — restrict to admin interface IPs only. Set filesystem permissions to 750, owned by asterisk:apache. For PCI-DSS or HIPAA compliance, consider LUKS filesystem encryption so recordings are unreadable if the physical drive is stolen.

SSH Hardening

# /etc/ssh/sshd_config
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
MaxAuthTries 3
LoginGraceTime 30
Port 2222
X11Forwarding no
AllowTcpForwarding no
Enter fullscreen mode Exit fullscreen mode

Before disabling password authentication, verify your SSH key works. Lock yourself out and you're calling the data center for KVM access. Change the port off 22 to eliminate 99% of automated scanning noise. Add fail2ban for SSH with 24-hour bans, same as for SIP.

The Biggest Risk Most Admins Overlook

Stale user accounts. Contact center turnover is brutal. Agents leave, their VICIdial accounts stay active. Those credentials are known to the former employee and potentially to anyone who shared a workstation. I audit environments with 500 active user accounts and 40 actual agents. Each of those 460 dormant accounts is a potential entry point.

Run a monthly audit: compare active VICIdial users against your HR headcount and deactivate every account without a warm body behind it. VICIdial doesn't support automatic account expiration, so this is a manual process or a cron job you write yourself.

The Quick Hardening Checklist

Print this. Run through it on every deployment:

  1. SVN revision 3848+ (patches the 2024 RCE chain)
  2. Firewall: default-deny on all interfaces
  3. SIP port restricted to carrier IPs only
  4. AMI port (5038) bound to localhost
  5. MySQL bound to localhost or private interface only
  6. No MySQL users with wildcard hosts
  7. allowguest=no and alwaysauthreject=yes in sip.conf
  8. Fail2ban running with 24-hour bans for SIP and SSH
  9. SIP ACLs configured for all trunks
  10. All SIP passwords 20+ characters, randomly generated
  11. HTTPS enforced, TLSv1.0/1.1 disabled
  12. Admin panel IP-restricted (VPN or whitelist)
  13. Default accounts (6666) deactivated, strong passwords on all admins
  14. SSH key-only auth, root login disabled, non-standard port
  15. Database config files have 640 permissions
  16. Recording directories restricted to apache/asterisk users
  17. OS security updates enabled (dnf-automatic for RHEL family)

Cloud Deployment Considerations

Running VICIdial in AWS, GCP, or DigitalOcean adds its own layer of security considerations. Cloud security groups are stateful packet filters, not application-aware firewalls — they don't inspect SIP traffic, don't understand NAT traversal, and don't rate-limit. You still need host-based firewalls (iptables/firewalld) and application-level protections (fail2ban, SIP ACLs) on every instance.

For proper VPC architecture: put database and telephony servers in a private subnet with no public IP. Web servers go in the public subnet and proxy all traffic. This mirrors the dual-NIC approach for bare metal. Never store AWS/GCP credentials on VICIdial servers — use instance roles (IAM roles in AWS, service accounts in GCP) for any cloud service interaction like S3 recording storage.

Network-Level SIP Protections

Beyond basic port filtering, rate-limit SIP request types at the firewall level:

# Rate-limit REGISTER attempts (prevents registration floods)
iptables -A INPUT -p udp --dport 5060 -m string --string "REGISTER" --algo bm \
  -m recent --name sip_register --set
iptables -A INPUT -p udp --dport 5060 -m string --string "REGISTER" --algo bm \
  -m recent --name sip_register --update --seconds 60 --hitcount 20 -j DROP
Enter fullscreen mode Exit fullscreen mode

This catches registration flood attacks that bypass fail2ban because they don't trigger authentication failures — they just overwhelm Asterisk with connection attempts.

Ongoing Maintenance

Security isn't a one-time project. Weekly: review fail2ban logs for patterns, check svn log for security patches, verify firewall rules haven't been modified. Monthly: rotate SIP trunk passwords with your carrier, review and deactivate departed staff accounts, test recording access controls by trying to access recordings without authentication, and review MySQL user privileges. Quarterly: full SVN update with regression testing, SSL certificate expiry check, firewall IP whitelist review, and external penetration test of the web interface. Annually: full security audit of all VICIdial servers, compliance review (PCI-DSS, HIPAA, TCPA) against current configuration, and verify your Asterisk version still receives security patches.

For the full 22-point hardening guide with every config snippet, fail2ban filter, PHP hardening directive, and cloud deployment considerations, see the complete article at ViciStack. If you'd rather not do this yourself, ViciStack deploys all of this as part of their standard managed service — continuous patching, proactive monitoring, and incident response included at $150/agent/month.

Originally published at https://vicistack.com/blog/vicidial-security-hardening/

Top comments (0)