Code Monkey home page Code Monkey logo

gixy's Introduction

GIXY

Mozilla Public License 2.0 Build Status Your feedback is greatly appreciated GitHub issues GitHub pull requests

Overview

Gixy is a tool to analyze Nginx configuration. The main goal of Gixy is to prevent security misconfiguration and automate flaw detection.

Currently supported Python versions are 2.7, 3.5, 3.6 and 3.7.

Disclaimer: Gixy is well tested only on GNU/Linux, other OSs may have some issues.

What it can do

Right now Gixy can find:

You can find things that Gixy is learning to detect at Issues labeled with "new plugin"

Installation

Gixy is distributed on PyPI. The best way to install it is with pip:

pip install gixy

Run Gixy and check results:

gixy

Usage

By default Gixy will try to analyze Nginx configuration placed in /etc/nginx/nginx.conf.

But you can always specify needed path:

$ gixy /etc/nginx/nginx.conf

==================== Results ===================

Problem: [http_splitting] Possible HTTP-Splitting vulnerability.
Description: Using variables that can contain "\n" may lead to http injection.
Additional info: https://github.com/yandex/gixy/blob/master/docs/ru/plugins/httpsplitting.md
Reason: At least variable "$action" can contain "\n"
Pseudo config:
include /etc/nginx/sites/default.conf;

	server {

		location ~ /v1/((?<action>[^.]*)\.json)?$ {
			add_header X-Action $action;
		}
	}


==================== Summary ===================
Total issues:
    Unspecified: 0
    Low: 0
    Medium: 0
    High: 1

Or skip some tests:

$ gixy --skips http_splitting /etc/nginx/nginx.conf

==================== Results ===================
No issues found.

==================== Summary ===================
Total issues:
    Unspecified: 0
    Low: 0
    Medium: 0
    High: 0

Or something else, you can find all other gixy arguments with the help command: gixy --help

Docker usage

Gixy is available as a Docker image from the Docker hub. To use it, mount the configuration that you want to analyse as a volume and provide the path to the configuration file when running the Gixy image.

$ docker run --rm -v `pwd`/nginx.conf:/etc/nginx/conf/nginx.conf yandex/gixy /etc/nginx/conf/nginx.conf

If you have an image that already contains your nginx configuration, you can share the configuration with the Gixy container as a volume.

$  docker run --rm --name nginx -d -v /etc/nginx
nginx:alpinef68f2833e986ae69c0a5375f9980dc7a70684a6c233a9535c2a837189f14e905

$  docker run --rm --volumes-from nginx yandex/gixy /etc/nginx/nginx.conf

==================== Results ===================
No issues found.

==================== Summary ===================
Total issues:
    Unspecified: 0
    Low: 0
    Medium: 0
    High: 0

Contributing

Contributions to Gixy are always welcome! You can help us in different ways:

  • Open an issue with suggestions for improvements and errors you're facing;
  • Fork this repository and submit a pull request;
  • Improve the documentation.

Code guidelines:

  • Python code style should follow pep8 standards whenever possible;
  • Pull requests with new plugins must have unit tests for it.

gixy's People

Contributors

atikhonov-avito avatar bachp avatar buglloc avatar darthfett avatar denyska avatar eidenschink avatar fertapric avatar florianjacob avatar innovativeinventor avatar jelly avatar jnovinger avatar mschwager avatar nevon avatar orf avatar plan-do-break-fix avatar polyzen avatar screeny05 avatar yoavtzelnick avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gixy's Issues

crashes on broken symlink

$ gixy ~/temp/nginx/nginx.conf
[nginx_parser] WARNING File not found: /etc/nginx/mime.types #OK
[nginx_parser] WARNING File not found: /home/user/temp/nginx/conf.d/*.conf #OK
Traceback (most recent call last):
File "/usr/local/bin/gixy", line 11, in
sys.exit(main())
File "/usr/local/lib/python3.5/dist-packages/gixy/cli/main.py", line 158, in main
yoda.audit(path, fdata, is_stdin=False)
File "/usr/local/lib/python3.5/dist-packages/gixy/core/manager.py", line 28, in audit
self.root = parser.parse(content=file_data.read(), path_info=file_path)
File "/usr/local/lib/python3.5/dist-packages/gixy/parser/nginx_parser.py", line 51, in parse
self.parse_block(parsed, root)
File "/usr/local/lib/python3.5/dist-packages/gixy/parser/nginx_parser.py", line 63, in parse_block
directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
File "/usr/local/lib/python3.5/dist-packages/gixy/parser/nginx_parser.py", line 77, in directive_factory
self.parse_block(children, inst)
File "/usr/local/lib/python3.5/dist-packages/gixy/parser/nginx_parser.py", line 61, in parse_block
self._resolve_include(parsed_args, parent)
File "/usr/local/lib/python3.5/dist-packages/gixy/parser/nginx_parser.py", line 109, in _resolve_include
return self._resolve_file_include(pattern=pattern, parent=parent)
File "/usr/local/lib/python3.5/dist-packages/gixy/parser/nginx_parser.py", line 117, in _resolve_file_include
self.parse_file(file_path, include)
File "/usr/local/lib/python3.5/dist-packages/gixy/parser/nginx_parser.py", line 26, in parse_file
content = open(path).read()
FileNotFoundError: [Errno 2] No such file or directory: '/home/user/temp/nginx/sites-enabled/symlink_nm.org'
$ ls /home/user/temp/nginx/sites-enabled/symlink_nm.org
/home/user/temp/nginx/sites-enabled/symlink_nm.org #broken symlink here

Failed to parse config with if and regex matching?

Hi!
I'm trying gixy 0.1.5 on nginx 1.10.3 config and getting this error:

[nginx_parser]	ERROR	Failed to parse config "/etc/nginx/conf.d/misc.conf": char 259 (line:12, col:1)

That part of the config reads

 12 # ddos
 13 if ($http_user_agent ~* "^WordPress.*; verifying pingback") {
 14   return 403;
 15 }

Commenting the if makes the parse error go away, I'm not sure exactly why though

detect format issue in add_header value

Consider we have the following nginx configuration:

server {
    listen 127.0.1.1:80;
    server_name _;
    add_header 'Access-Control-Allow-Headers' 'Content-Disposition,Content-Range,DNT,X-CustomHeader,Keep-Alive,
User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
    location / {
    }
}

On the above config there is a newline in the middle of the add_header value, and the there are no blanks at the start of the newline

    add_header 'Access-Control-Allow-Headers' 'Content-Disposition,Content-Range,DNT,X-CustomHeader,
Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'

In this case, when use postman or browers to performan the request on windows, the response head value will be cut as:

"Content-Disposition,Content-Range,DNT,X-CustomHeader,Keep-Alive"

So this is not we want. and may cause some potential problems.
This must be a rare case, but anyway if you add check for that it would be great.

Breaks when upstream name contains a period

This excerpt of a config file:

upstream ex.ample {
    server 127.0.0.1:9002;
}

Produces the following error:
[nginx_parser] ERROR Failed to parse config "nginx.conf": Expected ";" (at char 18), (line:1, col:19

I'm not sure if a period is technically allowed, but Nginx parses them just fine :)

Detect unsafe internal redirection

For example:

rewrite ^/(.*)/some$ /$1/ last;

location ~* ^/internal-proxy/(?<proxy_proto>https?)/(?<proxy_host>.*?)/(?<proxy_path>.*)$ {
    internal;

    proxy_pass $proxy_proto://$proxy_host/$proxy_path ;
    proxy_set_header Host $proxy_host;
}

Unfortunately, it is not easy to implement this.
Perhaps better for now just report about any internal locations and possible rewrites with INFO severity.

Gixy doesn't `exit 1` on files with syntax error

This commit introduced a strange behavior:

Current behavior

~/conf # cat default.conf
server
  listen 80;
  server_name _;
  return 404;
}
~/conf # gixy default.conf
[nginx_parser]	ERROR	Failed to parse config "default.conf": char 51 (line:5, col:1)

==================== Results ===================
No issues found.

==================== Summary ===================
Total issues:
    Unspecified: 0
    Low: 0
    Medium: 0
    High: 0
~/conf # echo $?
0

Expected behavior

~/conf # gixy default.conf
[nginx_parser]	ERROR	Failed to parse config "default.conf": char 51 (line:5, col:1)
~/conf # echo $?
1

nginx parser fail

Hello,

I have sometime this error while I lunch gixy. I think it's not really in relation with the file because it is parsed many time and it's only on the 18 time that it fail.

# gixy -d
[main]  DEBUG   logging initialized
[manager]       DEBUG   Audit config file: /etc/nginx/nginx.conf
[nginx_parser]  DEBUG   Parse file: /etc/nginx/mime.types
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/yunohost_admin.conf
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/yunohost_admin.conf.inc
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/yunohost_api.conf.inc
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/global.conf
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/domain2.tld.conf
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/yunohost_admin.conf.inc
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/yunohost_api.conf.inc

....

[nginx_parser]  DEBUG   Parse file: /etc/nginx/fastcgi_params
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/yunohost_panel.conf.inc
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/domain1.tld.d/monitorix.conf
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/yunohost_panel.conf.inc
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/yunohost_admin.conf.inc
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/yunohost_api.conf.inc
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/domain3.tld.conf
[nginx_parser]  DEBUG   Parse file: /etc/nginx/conf.d/domain3.tld.d/movim.conf
[nginx_parser]  DEBUG   Parse file: /etc/nginx/fastcgi_params
Traceback (most recent call last):
  File "/usr/local/bin/gixy", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/dist-packages/gixy/cli/main.py", line 169, in main
    yoda.audit(path, fdata, is_stdin=False)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 24, in audit
    self.root = parser.parse(content=file_data.read(), path_info=file_path)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 50, in parse
    self.parse_block(parsed, root)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 62, in parse_block
    directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 76, in directive_factory
    self.parse_block(children, inst)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 60, in parse_block
    self._resolve_include(parsed_args, parent)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 108, in _resolve_include
    return self._resolve_file_include(pattern=pattern, parent=parent)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 119, in _resolve_file_include
    self.parse_file(file_path, include)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 27, in parse_file
    return self.parse(content=content, root=root, path_info=path)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 50, in parse
    self.parse_block(parsed, root)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 62, in parse_block
    directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 76, in directive_factory
    self.parse_block(children, inst)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 60, in parse_block
    self._resolve_include(parsed_args, parent)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 108, in _resolve_include
    return self._resolve_file_include(pattern=pattern, parent=parent)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 119, in _resolve_file_include
    self.parse_file(file_path, include)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 27, in parse_file
    return self.parse(content=content, root=root, path_info=path)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 50, in parse
    self.parse_block(parsed, root)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 62, in parse_block
    directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
  File "/usr/local/lib/python2.7/dist-packages/gixy/parser/nginx_parser.py", line 72, in directive_factory
    args = [str(v).strip() for v in parsed_args[0]]
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

Support Python 2.6

[root@]# python -V
Python 2.6.6
[root@]# gixy /etc/nginx/conf.d/default.conf
Traceback (most recent call last):
File "/usr/bin/gixy", line 7, in
from gixy.cli.main import main
File "/usr/lib/python2.6/site-packages/gixy/cli/main.py", line 8, in
from gixy.formatters import get_all as formatters
File "/usr/lib/python2.6/site-packages/gixy/formatters/init.py", line 2, in
from gixy.formatters.base import BaseFormatter
File "/usr/lib/python2.6/site-packages/gixy/formatters/base.py", line 7
skip_parents = {block.Root, block.HttpBlock}
^
SyntaxError: invalid syntax

Problem: [origins] Validation regex for "origin" or "referrer" matches untrusted domain.

Hello. I'm curious the question about CORS

if ($http_origin ~* ((^https://www\.yandex\.ru)|(^https://ya\.ru)/)) {
	add_header 'Access-Control-Allow-Origin' "$http_origin";
	add_header 'Access-Control-Allow-Credentials' 'true';
}

The Host Header ABNF is as the following whatwg or rfc6454:

Origin                           = origin-or-null

origin-or-null              = origin / %x6E.75.6C.6C ; "null", case-sensitive
origin                           = scheme "://" host [ ":" port ]

The origin does not reveal a path. So use regex pattern ^ and $ is enough in my option. Are there any browser will include the path when send a ajax?

Добавить severity level INFO?

Порой бывает необходимо добавить какую-то информативную проверку, например, что используются internal-locations и на них надо бы посмотреть глазками или что есть regex локейшены без якорей.
Нужно таким проверкам найти место, варианты решения:

  • добавить severity level INFO
  • добавить новую команду, которая будет выводить различную инфу о конфиге и там уже сделать групировки/акценты/etc

Crashes on empty config files

While trying to work around #28 I tried adding a blank file to /etc/nginx/conf.d using sudo touch /etc/nginx/conf.d/blank.conf

This caused gixy to crash with a parsing error.

[nginx_parser]  ERROR   Failed to parse config "/etc/nginx/conf.d/blank.conf": Expected {Forward: ... | Forward: ... | Forward: ... | Forward: ... | {"include" Suppress:(<SPC><TAB><CR><LF>) {quoted string, starting with " ending with " | quoted string, starting with ' ending with ' | Re:('(?:\\([^\\s;]*\\)|\\$\\{\\w+\\}|[^\\s;(){}])+')} Suppress:(";")} | {W:(ABCD...) [{Suppress:(<SPC><TAB><CR><LF>) {quoted string, starting with " ending with " | quoted string, starting with ' ending with ' | Re:('(?:\\([^\\s;]*\\)|\\$\\{\\w+\\}|[^\\s;(){}])+')}}]... Suppress:(";")} | {Suppress:("# configuration file ") W:(ABCD...) Suppress:(":")} | Re:('#.*') | Forward: ...} (at char 0), (line:1, col:1)
Traceback (most recent call last):
  File "/usr/local/bin/gixy", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/dist-packages/gixy/cli/main.py", line 153, in main
    yoda.audit(path)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 24, in audit
    self._audit_recursive(self.root.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 39, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 39, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 39, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 39, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 34, in _audit_recursive
    self._update_variables(directive)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 49, in _update_variables
    for var in directive.variables:
  File "/usr/local/lib/python2.7/dist-packages/cached_property.py", line 26, in __get__
    value = obj.__dict__[self.func.__name__] = self.func(obj)
  File "/usr/local/lib/python2.7/dist-packages/gixy/directives/block.py", line 119, in variables
    for name, group in regexp.groups.items():
  File "/usr/local/lib/python2.7/dist-packages/cached_property.py", line 26, in __get__
    value = obj.__dict__[self.func.__name__] = self.func(obj)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/regexp.py", line 1004, in groups
    for name, parsed in extract_groups(self.parsed).items():
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/regexp.py", line 1025, in parsed
    self._parsed = sre_parse.parse(FIX_NAMED_GROUPS_RE.sub('(?P<\\1>', self.source))
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 707, in parse
    p = _parse_sub(source, pattern, 0)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 311, in _parse_sub
    itemsappend(_parse(source, state))
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 666, in _parse
    p = _parse_sub(source, state)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 311, in _parse_sub
    itemsappend(_parse(source, state))
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 688, in _parse
    code = _escape(source, this, state)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 301, in _escape
    raise error("bogus escape: %s" % repr(escape))
gixy.core.sre_parse.sre_constants.error: bogus escape: '\\x'

[nginx_parser] WARNING Skip unparseable block: "server"

my file is

user www-data;
worker_processes 4;
error_log /var/log/nginx/error.log warn;
#pid /var/run/nginx.pid;

legacy command

pid /run/nginx.pid;

events {
worker_connections 1024;
}

http {

##
# BRG Settings
##
client_max_body_size 10M;

include       /etc/nginx/mime.types;
default_type  application/octet-stream;

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';

access_log  /var/log/nginx/access.log  main;
# do not show the world whats going on
server_tokens off;
sendfile        on;
#tcp_nopush     on;
tcp_nopush on;
tcp_nodelay on;

keepalive_timeout  65;
types_hash_max_size 2048;

gzip  on;

limit_req_zone $binary_remote_addr zone=login_requests:10m rate=5r/m; #limits one request per minute

server {
    listen 80;
    server_name brgdrive.com;
    server_tokens off; #hides nginx version details
    charset utf-8;

    if ($request_method !~ ^(GET|HEAD|POST)$ ) #allows only request methods GET, HEAD, POST
    {
        return 405;
    }

    error_page 502 /custom_502.html;
    location = /custom_502.html {
            root /usr/share/nginx/html;
            internal;
    }

    error_page 503 /custom_503.html;
    location = /custom_503.html {
            root /usr/share/nginx/html;
            internal;
    }	

    location /pulse/ {
        proxy_pass http://drv_pulse_web:8001/pulse/; 
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /comms/ {
        #limit_req zone=one burst=<no value> nodelay; #LOGIN_REQUESTS_NGINX_RATE_LIMIT req is allowed per min and gets burst after NGINX_BURST number of request, shows 503 with nodelay
        #limit_rate_after 1000k; #Sets the initial amount after which the further transmission of a response to a client will be rate limited.
        #limit_rate 20k; #limits the response size to 20k
        proxy_pass http://drv_comms_web:8002/comms/;
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /viz/ {
        proxy_pass http://drv_viz_web:8003/viz/;
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /insights/ {
        proxy_pass http://drv_insights_web:8004/insights/;
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /magnet/ {
        proxy_pass http://drv_magnet_web:8005/magnet/;
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /toolbox/realtimestaffing/ {
        proxy_pass http://drv_toolbox_realtimestaffing_web:8007/toolbox/realtimestaffing/;
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /link/ {
        proxy_pass http://drv_link_web:8008/link/;
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /flow/ {
        proxy_pass http://drv_flow_web:8009/flow/;
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /alerts/ {
        proxy_pass http://drv_flow_web:8009/alerts/;
        proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /toolbox/employeerequisition/ {
        proxy_pass http://drv_toolbox_er_web:8010/toolbox/employeerequisition/;
        proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /mine/ {
        proxy_pass http://drv_mine_web:8011/mine/;
        proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /scenarios/ {
        proxy_pass http://drv_scenarios_web:8006/scenarios/;
        proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location /io/explorabi/ {
        proxy_pass http://drv_explorabi_web:8014/io/explorabi/;
        proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    # For Demo Puposes a redircet to static
    # Solution Ref: http://stackoverflow.com/questions/17685674/nginx-proxy-pass-with-remote-addr
    # location /magnet/ {
    #   #resolver 8.8.8.8;
    #   proxy_pass http://52.209.2.226/magnet/;
    #   proxy_set_header  Host  $host;
    #   proxy_set_header  X-Real-IP $remote_addr;
    #	}
    location /static/ {
        proxy_pass http://drv_static:80/static/;
        proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    }
    #### Core Stuff ###   
    
    location = /login/ {
        limit_req zone=login_requests burst=6 nodelay;
        proxy_pass http://drv_core_web:8000;
        proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
    location = /login/authenticate_user/ {
        limit_req zone=login_requests burst=6 nodelay;
        proxy_pass http://drv_core_web:8000;
        proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location / {
        proxy_pass http://drv_core_web:8000;
        proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
        
    
}

}
daemon off;

[request] nginx root directory

Hello,

I'm not a Python savvy otherwise I would have proposed a PR (might come if no one else judge it useful).
I'd like to be able to verify a configuration before it lands into Kubernetes/Configmap.
Files could be moved to /etc/nginx prior to running gixy but in the current state if I test a file in /a/b/c/nginx.conf that includes other files, it will fail saying "[nginx_parser] WARNING File not found: /etc/nginx/conf.d/internal.conf".
It's not looking for that "conf.d/internal.conf" file inside the directory I'm currently located (or based on the path to nginx.conf but straight into /etc/nginx which doesn't exist.

Thank you

Allow gixy to accept multiple .config files at once

If you have a few different config files it would be nice to be able to run:

gixy *.conf

and have it check all config files. To allow this Gixy should be extended to accept any number of config files. It seems like it should be pretty simple to add support for this in the cli module.

Parsing issues

# gixy
[nginx_parser]	ERROR	Failed to parse config "/etc/nginx/conf.d/stub_status.conf": Expected end of text (at char 174), (line:14, col:1)
[context]	INFO	Can't find variable 'user'
[context]	INFO	Can't find variable 'user'
[context]	INFO	Can't find variable 'user'
[context]	INFO	Can't find variable 'user'
[context]	INFO	Can't find variable 'user'
  1. The file stub_status.conf is pretty simple. It looks like a bug.
  2. Looks like the gixy doesn't know auth_request_set parameter.
        auth_request_set $user $upstream_http_x_user_id;
        proxy_set_header X-User-ID $user;

$ cat -v /etc/nginx/conf.d/stub_status.conf

#
# Ansible managed
#

server {
  listen 127.0.0.10:80;

  location = /connection_statistics {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
  }
}

od -c /etc/nginx/conf.d/stub_status.conf

0000000   #  \n   #       A   n   s   i   b   l   e       m   a   n   a
0000020   g   e   d  \n   #  \n  \n   s   e   r   v   e   r       {  \n
0000040           l   i   s   t   e   n       1   2   7   .   0   .   0
0000060   .   1   0   :   8   0   ;  \n  \n           l   o   c   a   t
0000100   i   o   n       =       /   c   o   n   n   e   c   t   i   o
0000120   n   _   s   t   a   t   i   s   t   i   c   s       {  \n
0000140               s   t   u   b   _   s   t   a   t   u   s       o
0000160   n   ;  \n                   a   c   c   e   s   s   _   l   o
0000200   g       o   f   f   ;  \n                   a   l   l   o   w
0000220       1   2   7   .   0   .   0   .   1   ;  \n
0000240   d   e   n   y       a   l   l   ;  \n           }  \n   }  \n
0000260  \n
0000261

Better nginx config detection

Current code doesn't work on other possible configuration styles (ex.: new lines)
def _is_nginx_file(file_path): s = open(file_path).read() return 'server {' in s or 'http {' in s

host_spoofing trouble

I don't understand how to spoof the host when using $http_host.

When I use X-Forwarded-Host: evil.com ,the $http_host doesn't return evil.com.

broken parser

Gixy v0.1.3 from pip fails to parse the 'server' section in config. nginx itself of course succeeds in it.

$ ~/.local/bin/gixy -d /etc/nginx/sites-enabled/qutim.org 
[main]	DEBUG	logging initialized
[nginx_parser]	DEBUG	Parse file: /etc/nginx/sites-enabled/qutim.org
[nginx_parser]	WARNING	Skip unparseable block: "server"
$ cat /etc/nginx/sites-enabled/qutim.org 
upstream prosody {
	server 127.0.0.1:5280;
}

upstream sorokdva {
	server sorokdva.net:443;
}

server {
	listen	[::]:80		default_server;
	listen	[::]:443	default_server	ssl;

	server_name	qutim.org;
	access_log	/var/log/nginx/qutim.org.access.log	main;
	error_log	/var/log/nginx/qutim.org.error.log	error;
	log_subrequest	on;
	rewrite_log on;

	fastcgi_index			index.php;
	include				fastcgi_params;
	fastcgi_param			SCRIPT_FILENAME		$document_root$fastcgi_script_name;
	fastcgi_intercept_errors	on;
	
	charset				utf-8;
	index				index.php;
	root				/srv/nginx/qutim.org;
	
	# ssl_certificate			/etc/certs/qutim.org.cert.pem;
	# ssl_certificate_key		/etc/certs/qutim.org.cert.key;
	ssl_certificate			/etc/letsencrypt/live/qutim.org/fullchain.pem;
	ssl_certificate_key		/etc/letsencrypt/live/qutim.org/privkey.pem;
	include				ssl_params;
	add_header			Strict-Transport-Security	"max-age=31536000";

	# error_page	404	/404;
	# error_page	500 502 503 504	/50x;
	error_page			404	/?page=404;
	error_page			403	/?page=403;

	location ~ /\.ht {
		return 403;
	}

	location ~ /config\.ini {
		return 403;
	}

	location ~ ^/upload/ {
		try_files	$uri		=404;
		if ($request_filename ~* ^.*?/(\d+_)([^/]+)$)
		{
			set $filename $2;
			add_header Content-Disposition "attachment; filename=$filename";
		}
	}

	location ~ ^/gentoo {
		rewrite		^/gentoo.*$	/download.php?id=6&f=cXV0aW0ub3ZlcmxheQ==	redirect;
	}

	location ~ ^/private/ {
		rewrite	^/private/api/([^/]+)/([^/]+)$ /ajax.php?class=privateapi&action=$1$2	last;
	}

	location ~ ^/(ajax|index|download|avatar|stats)\.php$ {
		if ($arg_class = "privateapi") {
			set $privateapi "1";
		}
		set $localconnection "0";
		if ($remote_addr = "127.0.0.1") {
			set $localconnection "1";
		}
		if ($remote_addr = "::ffff:127.0.0.1") {
			set $localconnection "1";
		}
		set $isdenied $privateapi$localconnection;

		if ($isdenied = "10") {
			return 403;
		}

		try_files	$fastcgi_script_name	=404;
		fastcgi_pass	unix:/var/run/php5-fpm.sock;
		include	fastcgi_params;
		fastcgi_param	SCRIPT_FILENAME $document_root$fastcgi_script_name;
	}

	location ~ ^/(templates|locale|src|cache)/ {
		return 403;
	}

	location /.well-known/ {
		try_files	$uri		=404;
	}

	location /candy/ {
		try_files	$uri		=404;
	}

	location ~ ^/(styles|js|icons|client_stuff|images|ocs|debian)/ {
		autoindex	off;
		try_files	$uri		=404;
	}

	location = /favicon.ico {
		access_log	off;
		log_not_found	off;
	}

	location ~ ^/dwnl/.*$ {
		# Pretty urls
		rewrite		^/dwnl/(\d+)/([^/]*)$		/download.php?id=$1&f=$2&t=file			last;
	}

	location ~ \.(js|css|jpg|png|gif|ico|html?|txt)$ {
		try_files	$uri		=404;
	}

	location / {
		# User links
		rewrite		^/~([^/]+)(.*)$			/user/$1$2;
		rewrite		^/user/([^/]+)/([^/]+)/ajax/?$	/ajax.php?class=user&username=$1&action=$2	last;
		rewrite		^/user/([^/]+)/([^/]+).*/?$	/user?username=$1&action=$2;
		rewrite		^/user/([^/]+)/?$		/user?username=$1;

		# File links
		rewrite		^/file/([^/]+)/([^/]+).*/?$	/file?id=$1&action=$2;
		rewrite		^/file/([^/]+)/?$		/file?id=$1;

		# Ajax
		rewrite		^/ajax/([^/]+)/([^/]+).*/?$	/ajax.php?class=$1&action=$2			last;
		rewrite		^/ajax/([^/]+)/?$		/ajax.php?class=$1&action=process		last;

		# Stats
		rewrite		^/stats$			/stats.php					last;

		# Everything other is a controller
		rewrite		^/([^/]*).*$			/index.php?page=$1				last;
	}

	# Prosody BOSH
	location /http-bind/ {
		proxy_pass  http://prosody/http-bind/;
		proxy_set_header Host $host;
		proxy_buffering off;
		tcp_nodelay on;
	}

	# Prosody logs
	location /logs/ {
		proxy_pass https://sorokdva/logs/;
		proxy_redirect off;
	}

	location /forum/ {
		location ~ /forum/(config\.php|common\.php|includes|cache|files|store|images/avatars/upload) {
			return		403;
		}
	
		location ~ \.php$ {
			try_files	$fastcgi_script_name	=404;
			fastcgi_pass	unix:/var/run/php5-fpm.sock;
			include	fastcgi_params;
			fastcgi_param	SCRIPT_FILENAME $document_root$fastcgi_script_name;
		}
	}
}

Crashes on empty conf.d directory

I have the default Ubuntu nginx.conf that contains the line include /etc/nginx/conf.d/*.conf;
For me that directory happens to be empty and this causes gixy to crash.

I would either expect it ignore the empty directory or have an additional analysis rule that will flag that as an error or warning.

Here's the stack trace

[nginx_parser]  WARNING File not found: /etc/nginx/conf.d/*.conf
Traceback (most recent call last):
  File "/usr/local/bin/gixy", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/dist-packages/gixy/cli/main.py", line 153, in main
    yoda.audit(path)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 24, in audit
    self._audit_recursive(self.root.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 39, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 39, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 39, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 39, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 34, in _audit_recursive
    self._update_variables(directive)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 49, in _update_variables
    for var in directive.variables:
  File "/usr/local/lib/python2.7/dist-packages/cached_property.py", line 26, in __get__
    value = obj.__dict__[self.func.__name__] = self.func(obj)
  File "/usr/local/lib/python2.7/dist-packages/gixy/directives/block.py", line 119, in variables
    for name, group in regexp.groups.items():
  File "/usr/local/lib/python2.7/dist-packages/cached_property.py", line 26, in __get__
    value = obj.__dict__[self.func.__name__] = self.func(obj)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/regexp.py", line 1004, in groups
    for name, parsed in extract_groups(self.parsed).items():
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/regexp.py", line 1025, in parsed
    self._parsed = sre_parse.parse(FIX_NAMED_GROUPS_RE.sub('(?P<\\1>', self.source))
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 707, in parse
    p = _parse_sub(source, pattern, 0)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 311, in _parse_sub
    itemsappend(_parse(source, state))
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 666, in _parse
    p = _parse_sub(source, state)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 311, in _parse_sub
    itemsappend(_parse(source, state))
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 688, in _parse
    code = _escape(source, this, state)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 301, in _escape
    raise error("bogus escape: %s" % repr(escape))
gixy.core.sre_parse.sre_constants.error: bogus escape: '\\x'

[regexp] CRITICAL Failed to parse regex: \?.*\=restapi.*+ (multiple repeat)

server {
    listen 80 default_server;
    server_name localhost;
    location ~* \?.*\=restapi.*+ {
    }
}

gixy default
[regexp] CRITICAL Failed to parse regex: ?.=restapi.+ (multiple repeat)
Traceback (most recent call last):
File "/home/user/.local/bin/gixy", line 11, in
sys.exit(main())
File "/home/user/.local/lib/python2.7/site-packages/gixy/cli/main.py", line 166, in main
yoda.audit(path, fdata, is_stdin=False)
File "/home/user/.local/lib/python2.7/site-packages/gixy/core/manager.py", line 27, in audit
self._audit_recursive(self.root.children)
File "/home/user/.local/lib/python2.7/site-packages/gixy/core/manager.py", line 53, in _audit_recursive
self._audit_recursive(directive.children)
File "/home/user/.local/lib/python2.7/site-packages/gixy/core/manager.py", line 48, in _audit_recursive
self._update_variables(directive)
File "/home/user/.local/lib/python2.7/site-packages/gixy/core/manager.py", line 63, in _update_variables
for var in directive.variables:
File "/home/user/.local/lib/python2.7/site-packages/cached_property.py", line 26, in get
value = obj.dict[self.func.name] = self.func(obj)
File "/home/user/.local/lib/python2.7/site-packages/gixy/directives/block.py", line 119, in variables
for name, group in regexp.groups.items():
File "/home/user/.local/lib/python2.7/site-packages/cached_property.py", line 26, in get
value = obj.dict[self.func.name] = self.func(obj)
File "/home/user/.local/lib/python2.7/site-packages/gixy/core/regexp.py", line 1004, in groups
for name, parsed in extract_groups(self.parsed).items():
File "/home/user/.local/lib/python2.7/site-packages/gixy/core/regexp.py", line 1029, in parsed
raise e
gixy.core.sre_parse.sre_constants.error: multiple repeat

nested context-vars aren't found

minimal example to reproduce:

server {
        location / {
                if ($request_filename ~* ^.*?/(\d+_)([^/]+)$)
                {
                        set $filename $2;
                        add_header Content-Disposition "attachment; filename=$filename";                               
                }                                                                                                      
        }                                                                                                              
}

Gives output:

[context]	INFO	Can't find variable '2'

Btw, such notes definitely lack context or line information, so in long config it's nearly impossible to find which one $2 drives parser mad.

Плохо работает структурный анализ реферера

Если не указывать список валидных рефереров то не работает структурный анализ, например, для этого конфига Gixy говорит что все ОК:

http {
	if ($http_referer !~ "https://example.com/"){
		add_header X-Frame-Options SAMEORIGIN;
	}
}

False positive while checking default wordpress config

Here is default nginx config for WP: https://codex.wordpress.org/Nginx
And here is a line:

rewrite /wp-admin$ $scheme://$host$uri/ permanent;

Gixy warns us with next issue:

>> Problem: [http_splitting] Possible HTTP-Splitting vulnerability. Description: Using variables that can contain "\n" or "\r" may lead to http injection. ... Reason: At least variable "$uri" can contain "\n"

But this is false positive as Rewrite directive isn't vulnerable to CRLF.

[regexp] CRITICAL Failed to parse regex (nothing to repeat)

Here's the top line of the error I'm seeing when trying Gixy on my nginx.conf...

[regexp]        CRITICAL        Failed to parse regex: (*UTF8)^/(?<prefix>(?:p/\d+/)?)(?<edition>(?:jp|de)/)?(?<page>(?!jp/|de/)\w+/[\p{Hiragana}\p{Katakana}\p{Han}\w-]+)/?$ (nothing to repeat)

Feature Request: Checkstyle output

Yo,

This is super cool! It would be heaps easier to integrate into our tooling if it used checkstyle (or another standard linter output) though. Would that be something you'd consider?

<3

Crashes on config with lua options

I have custom nginx build with enabled support for lua (lua-nginx-module-0.10.0). I have declared a dynamic variable using set_by_lua_file $myvar and this can be an issue.

Part of my config

...
    set_by_lua_file $latest_ver conf/var_factory.lua;
...

Here's the stack trace

[context]	INFO	Can't find variable '1'
[context]	INFO	Can't find variable 'latest_ver'
[context]	INFO	Can't find variable 'latest_ver'
[context]	INFO	Can't find variable 'latest_ver'
Traceback (most recent call last):
  File "/usr/local/bin/gixy", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/dist-packages/gixy/cli/main.py", line 158, in main
    yoda.audit(path, fdata, is_stdin=False)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 31, in audit
    self._audit_recursive(self.root.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 46, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 46, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 46, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 41, in _audit_recursive
    self._update_variables(directive)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/manager.py", line 56, in _update_variables
    for var in directive.variables:
  File "/usr/local/lib/python2.7/dist-packages/gixy/directives/directive.py", line 118, in variables
    for name, group in regexp.groups.items():
  File "/usr/local/lib/python2.7/dist-packages/cached_property.py", line 26, in __get__
    value = obj.__dict__[self.func.__name__] = self.func(obj)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/regexp.py", line 1004, in groups
    for name, parsed in extract_groups(self.parsed).items():
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/regexp.py", line 1025, in parsed
    self._parsed = sre_parse.parse(FIX_NAMED_GROUPS_RE.sub('(?P<\\1>', self.source))
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 707, in parse
    p = _parse_sub(source, pattern, 0)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 311, in _parse_sub
    itemsappend(_parse(source, state))
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 666, in _parse
    p = _parse_sub(source, state)
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 311, in _parse_sub
    itemsappend(_parse(source, state))
  File "/usr/local/lib/python2.7/dist-packages/gixy/core/sre_parse/sre_parse.py", line 644, in _parse
    raise error("bad character in group name")
gixy.core.sre_parse.sre_constants.error: bad c

Gixy v0.1.4

[feature request] Check for default location with regexp server name

Consider we have the following nginx configuration:

server {
    listen 127.0.1.2:80;
    server_name ~^([a-z0-9]+).site.com;
    rewrite (.*) https://$server_name/$1 redirect;
}

And if it happens so that this is the first server for that IP:port and there is no default server for that IP:port - this server automatically becomes default server for that IP:port. In that case an attacker can reveal server_name part of nginx config with the following request:

$ curl -I http://127.0.1.2/ -H Host: --http1.0
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.13.6
Date: Tue, 17 Apr 2018 11:48:46 GMT
Content-Type: text/html
Content-Length: 161
Connection: close
Location: https://~^([a-z0-9]+).site.com//

This must be a rare case, and not too much information is revealed, but anyway if you add check for that it would be great.

Summary count not accurate


==================== Results ===================

Problem: [origins] Validation regex for "origin" or "referrer" matches untrusted domain.
Severity: HIGH <-------
Description: Improve the regular expression to match only trusted referrers.
Additional info: https://github.com/yandex/gixy/blob/master/docs/en/plugins/origins.md
Reason: Regex matches "https://www.yandex.ru.evil.com" as a valid origin.
Pseudo config:
if ($http_origin ~* ((^https://www\.yandex\.ru)|(^https://ya\.ru)/)) {
}


==================== Summary ===================
Total issues:
    Unspecified: 0
    Low: 0
    Medium: 1 <-------
    High: 0

Shows High in the Results section but the Summary count it as showing Medium.

RecursionError: maximum recursion depth exceeded while calling a Python object

Hi:

I am using gixy to analyze nginx conf files, but here comes an exception, I do not know whether it is related to "recursive import".

My Env:
v0.1.20
python3

Traceback (most recent call last):
   File "/home/tops/bin/gixy", line 11, in <module>
     load_entry_point('gixy==0.1.20', 'console_scripts','gixy')()
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/cli/main.py", line 168, in main
     yoda.audit(path, fdata, is_stdin=False)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/core/manager.py", line 24, in audit
     self.root = parser.parse(content=file_data.read(), path_info=file_path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 61, in parse_block
     self._resolve_include(parsed_args, parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 109, in _resolve_include
     return self._resolve_file_include(pattern=pattern, parent=parent)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 120, in _resolve_file_include
     self.parse_file(file_path, include)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 28, in parse_file
     return self.parse(content=content, root=root, path_info=path)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 51, in parse
     self.parse_block(parsed, root)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 63, in parse_block
     directive_inst = self.directive_factory(parsed_type, parsed_name, parsed_args)
   File "/home/tops/lib/python3.7/site-packages/gixy-0.1.20-py3.7.egg/gixy/parser/nginx_parser.py", line 77, in directive_factory
     self.parse_block(children, inst)

Gixy fails to parse non-english characters

Gixy fails to parse a configuration file containing utf-8 characters.

For instance:

rewrite ^/24-01/เครองแตงกาย/เสอฮด/$ https://$host/24-01/ permanent;

It raises following exception:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 8-10: ordinal not in range(128)

Сужать boundary set для значений переменных на основании проверок в условиях

К примеру, в ситуации:

if ($uri ~ "[ \r\n\f\t]") {
    return 400;
}

Необходимо учесть, что переменные $request_uri, $document_uri и $uri не могут содержать символов \r\n\f\t без сторонней помощи.
Иначе некоторые проверки (например, http_splitting) могут фолзить.

The hostspoofing recommended fix is wrong

The recommendation for remediating host spoofing in https://github.com/yandex/gixy/blob/master/docs/en/plugins/hostspoofing.md is wrong.

The recommendation is currently to use $host instead of $http_host, which does not remediate the issue and in certain cases makes it worse (vulnerable when otherwise would not be).

The value of the $host variable is set like so:

in this order of precedence: host name from the request line, or host name from the “Host” request header field, or the server name matching a request

Which means that (after recommended fix), not only can an attacker inject a different host from the Host header, but also from the request line. In cases where a filter/IDS is applied solely on the Host header, the fix makes it vulnerable via the request line.

The proper fix to this issue should be to use validated $server_name or a whitelist of accepted $host values.

[nginx_parser] WARNING Skip unparseable block: "server"

i get this warning when scanning my nginx.conf file:
[nginx_parser] WARNING Skip unparseable block: "server"

most of my configuration code is inside the server block, is there something wrong my config file?
config file works accordingly when i run my application

Licensing issue?

Looks like you're using part of the code which is licensed with "CNRI's Python license".
I meant this sre_parse.py file and another one in the folder.

If I remember correct, CNRI Py Li is not compatible with Mozilla License which is chosen by you for this project.

[regexp] Add internal opition settings support

I have the following code in my nginx config:

# new frontend base routes
location /public/ {
    alias /usr/share/nginx/html;

    location ~ "^/public/[0-9a-fA-F.]{32}/forPhp/(?<path>(?U).*)$" {
        try_files /forPhp/$path =404;
    }
}

This code produces the following error while validating it with gixy:

[regexp]	CRITICAL	Failed to parse regex: ^/public/[0-9a-fA-F.]{32}/forPhp/(?<path>(?U).*)$ (unexpected end of pattern)
Traceback (most recent call last):
  File "/usr/local/bin/gixy", line 11, in <module>
    load_entry_point('gixy==0.1.9', 'console_scripts', 'gixy')()
  File "/usr/local/lib/python2.7/site-packages/gixy-0.1.9-py2.7.egg/gixy/cli/main.py", line 169, in main
    yoda.audit(path, fdata, is_stdin=False)
  File "/usr/local/lib/python2.7/site-packages/gixy-0.1.9-py2.7.egg/gixy/core/manager.py", line 27, in audit
    self._audit_recursive(self.root.children)
  File "/usr/local/lib/python2.7/site-packages/gixy-0.1.9-py2.7.egg/gixy/core/manager.py", line 53, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/site-packages/gixy-0.1.9-py2.7.egg/gixy/core/manager.py", line 53, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/site-packages/gixy-0.1.9-py2.7.egg/gixy/core/manager.py", line 53, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/site-packages/gixy-0.1.9-py2.7.egg/gixy/core/manager.py", line 53, in _audit_recursive
    self._audit_recursive(directive.children)
  File "/usr/local/lib/python2.7/site-packages/gixy-0.1.9-py2.7.egg/gixy/core/manager.py", line 48, in _audit_recursive
    self._update_variables(directive)
  File "/usr/local/lib/python2.7/site-packages/gixy-0.1.9-py2.7.egg/gixy/core/manager.py", line 63, in _update_variables
    for var in directive.variables:
  File "/usr/local/lib/python2.7/site-packages/cached_property-1.4.0-py2.7.egg/cached_property.py", line 32, in __get__
    value = obj.__dict__[self.func.__name__] = self.func(obj)
  File "/usr/local/lib/python2.7/site-packages/gixy-0.1.9-py2.7.egg/gixy/directives/block.py", line 119, in variables
    for name, group in regexp.groups.items():
  File "/usr/local/lib/python2.7/site-packages/cached_property-1.4.0-py2.7.egg/cached_property.py", line 32, in __get__
    value = obj.__dict__[self.func.__name__] = self.func(obj)
  File "/usr/local/lib/python2.7/site-packages/gixy-0.1.9-py2.7.egg/gixy/core/regexp.py", line 1004, in groups
    for name, parsed in extract_groups(self.parsed).items():
  File "/usr/local/lib/python2.7/site-packages/gixy-0.1.9-py2.7.egg/gixy/core/regexp.py", line 1029, in parsed
    raise e
gixy.core.sre_parse.sre_constants.error: unexpected end of pattern

Not sure, maybe a duplicate of #57

False positives of Alias Traversal

Description: Using alias in a prefixed location that doesn't ends with directory separator could lead to path traversal vulnerability. 
Additional info: https://github.com/yandex/gixy/blob/master/docs/en/plugins/aliastraversal.md
Pseudo config:

server {
	server_name xxx;

	location /bangumi {
		alias /www/bangumi;
	}

	location /ariang {
		alias /www/ariang;
	}
}

Which cannot perform a alias traversal attack.

Detection of proxying to 3rd-party hosts

This is very similar to ssrf, but we need to report ant 3rd-party hosts in upstreams, e.g.:

location /counter {
    proxy_pass http://some.cool.metrics.ru;
}

Todo:

  • detecting proxied hosts (variables, maps, etc)
  • exclude fp with proxy_pass http://backend;
  • lower severity level if user data doesn't sent

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.