Issues (850)

Security Analysis    4 potential vulnerabilities

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection (1)
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection (2)
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting (1)
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

admin/class-getpaid-anonymization-logs.php (3 issues)

1
<?php
2
/**
3
 * GetPaid Anonymization Logs Admin
4
 *
5
 * @package GetPaid
6
 * @subpackage Admin
7
 * @since 2.8.22
8
 */
9
10
defined( 'ABSPATH' ) || exit;
11
12
/**
13
 * GetPaid_Anonymization_Logs Class
14
 */
15
class GetPaid_Anonymization_Logs {
16
17
    /**
18
     * Anonymization logs page
19
     */
20
    public function display_logs() {
21
        // Check user capabilities
22
        if ( ! current_user_can( 'manage_options' ) ) {
23
            return;
24
        }
25
26
        // Get current page number
27
        $page = isset( $_GET['paged'] ) ? absint( $_GET['paged'] ) : 1;
28
        $per_page = 20;
29
30
        // Fetch logs
31
        $logs = $this->get_logs( $page, $per_page );
32
        $total_logs = $this->get_total_logs();
33
34
        // Prepare pagination
35
        $pagination = paginate_links(
36
            array(
0 ignored issues
show
Security Variable Injection introduced by
array('base' => add_quer...e), 'current' => $page) can contain request data and is used in variable name context(s) leading to a potential security vulnerability.

2 paths for user data to reach this point

  1. Path: Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri in wordpress/wp-includes/functions.php on line 1132
  1. Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri
    in wordpress/wp-includes/functions.php on line 1132
  2. $uri . '?' is assigned to $base
    in wordpress/wp-includes/functions.php on line 1165
  3. $protocol . $base . $ret . $frag is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1191
  4. Data is passed through rtrim(), and rtrim($ret, '?') is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1192
  5. Data is passed through str_replace(), and str_replace('?#', '#', $ret) is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1193
  6. $ret is returned
    in wordpress/wp-includes/functions.php on line 1194
  2. Path: Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri in wordpress/wp-includes/functions.php on line 1138
  1. Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri
    in wordpress/wp-includes/functions.php on line 1138
  2. $uri . '?' is assigned to $base
    in wordpress/wp-includes/functions.php on line 1165
  3. $protocol . $base . $ret . $frag is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1191
  4. Data is passed through rtrim(), and rtrim($ret, '?') is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1192
  5. Data is passed through str_replace(), and str_replace('?#', '#', $ret) is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1193
  6. $ret is returned
    in wordpress/wp-includes/functions.php on line 1194

Used in variable context

  1. paginate_links() is called
    in includes/admin/class-getpaid-anonymization-logs.php on line 36
  2. Enters via parameter $args
    in wordpress/wp-includes/general-template.php on line 4469
  3. wp_parse_args() is called
    in wordpress/wp-includes/general-template.php on line 4506
  4. Enters via parameter $args
    in wordpress/wp-includes/functions.php on line 4821
  5. wp_parse_str() is called
    in wordpress/wp-includes/functions.php on line 4827
  6. Enters via parameter $input_string
    in wordpress/wp-includes/formatting.php on line 5148
  7. parse_str() is called
    in wordpress/wp-includes/formatting.php on line 5149

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
37
				'base'      => add_query_arg( 'paged', '%#%' ),
38
				'format'    => '',
39
				'prev_text' => __( '&laquo;', 'invoicing' ),
40
				'next_text' => __( '&raquo;', 'invoicing' ),
41
				'total'     => ceil( $total_logs / $per_page ),
42
				'current'   => $page,
43
            )
44
        );
45
46
        ?>
47
        <div class="wrap getpaid-anonymization-logs">
48
            <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
49
            <div class="tablenav top">
50
                <div class="alignleft actions">
51
                    <form method="get">
52
                        <input type="hidden" name="page" value="wpinv-anonymization-logs">
53
                        <label for="filter-by-date" class="screen-reader-text"><?php _e( 'Filter by date', 'invoicing' ); ?></label>
54
                        <select name="m" id="filter-by-date">
55
                            <option value="0"><?php _e( 'All dates', 'invoicing' ); ?></option>
56
                            <?php
57
                            $months = $this->get_log_months();
58
                            foreach ( $months as $month ) {
59
                                $selected = ( isset( $_GET['m'] ) && $_GET['m'] == $month->month ) ? ' selected="selected"' : '';
60
                                echo '<option value="' . esc_attr( $month->month ) . '"' . $selected . '>' . esc_html( $month->month_name . ' ' . $month->year ) . '</option>';
61
                            }
62
                            ?>
63
                        </select>
64
                        <?php submit_button( __( 'Filter', 'invoicing' ), '', 'filter_action', false ); ?>
65
                    </form>
66
                </div>
67
            </div>
68
            <table class="wp-list-table widefat fixed striped">
69
                <thead>
70
                    <tr>
71
                        <th><?php _e( 'Log ID', 'invoicing' ); ?></th>
72
                        <th><?php _e( 'User', 'invoicing' ); ?></th>
73
                        <th><?php _e( 'Action', 'invoicing' ); ?></th>
74
                        <th><?php _e( 'Date', 'invoicing' ); ?></th>
75
                        <th><?php _e( 'Details', 'invoicing' ); ?></th>
76
                    </tr>
77
                </thead>
78
                <tbody>
79
                    <?php if ( empty( $logs ) ) : ?>
80
                        <tr>
81
                            <td colspan="5"><?php _e( 'No anonymization logs found.', 'invoicing' ); ?></td>
82
                        </tr>
83
                    <?php else : ?>
84
                        <?php
85
                        foreach ( $logs as $log ) :
86
                            $additional_info = json_decode( $log->additional_info, true );
87
                        ?>
88
                            <tr>
89
                                <td><?php echo esc_html( $log->log_id ); ?></td>
90
                                <td>
91
                                    <?php
92
                                    $user_edit_link = get_edit_user_link( $log->user_id );
93
                                    if ( $user_edit_link ) {
94
                                        echo '<a href="' . esc_url( $user_edit_link ) . '">' . esc_html( $log->user_id ) . '</a>';
95
                                    } else {
96
                                        echo esc_html( $log->user_id );
97
                                    }
98
                                    ?>
99
                                </td>
100
                                <td><?php echo esc_html( ucfirst( $log->action ) ); ?></td>
101
                                <td><?php echo esc_html( get_date_from_gmt( $log->timestamp, 'F j, Y g:i a' ) ); ?></td>
102
                                <td>
103
                                    <button class="button-link toggle-details" type="button" aria-expanded="false">
104
                                        <span class="screen-reader-text"><?php _e( 'Show more details', 'invoicing' ); ?></span>
105
                                        <span class="dashicons dashicons-arrow-down-alt2"></span>
106
                                    </button>
107
                                </td>
108
                            </tr>
109
                            <tr class="log-details" style="display:none;">
110
                                <td colspan="5">
111
                                    <div class="log-details-content">
112
                                        <table class="widefat fixed">
113
                                            <tbody>
114
                                                <tr>
115
                                                    <th><?php _e( 'Data Type', 'invoicing' ); ?></th>
116
                                                    <td><?php echo esc_html( $log->data_type ); ?></td>
117
                                                </tr>
118
                                                <?php if ( is_array( $additional_info ) ) : ?>
119
                                                    <tr>
120
                                                        <th><?php _e( 'Additional Information', 'invoicing' ); ?></th>
121
                                                        <td>
122
                                                            <table class="widefat fixed">
123
                                                                <tbody>
124
                                                                    <?php foreach ( $additional_info as $key => $value ) : ?>
125
                                                                        <tr>
126
                                                                            <th><?php echo esc_html( $key ); ?></th>
127
                                                                            <td><?php echo esc_html( $value ); ?></td>
128
                                                                        </tr>
129
                                                                    <?php endforeach; ?>
130
                                                                </tbody>
131
                                                            </table>
132
                                                        </td>
133
                                                    </tr>
134
                                                <?php endif; ?>
135
                                            </tbody>
136
                                        </table>
137
                                    </div>
138
                                </td>
139
                            </tr>
140
                        <?php endforeach; ?>
141
                    <?php endif; ?>
142
                </tbody>
143
            </table>
144
            <?php if ( $pagination ) : ?>
145
                <div class="tablenav bottom">
146
                    <div class="tablenav-pages">
147
                        <?php echo $pagination; ?>
0 ignored issues
show
Are you sure $pagination of type string|string[] can be used in echo? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

147
                        <?php echo /** @scrutinizer ignore-type */ $pagination; ?>
Loading history...
Security Cross-Site Scripting introduced by
$pagination can contain request data and is used in output context(s) leading to a potential security vulnerability.

2 paths for user data to reach this point

  1. Path: Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri in wordpress/wp-includes/functions.php on line 1132
  1. Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri
    in wordpress/wp-includes/functions.php on line 1132
  2. $uri . '?' is assigned to $base
    in wordpress/wp-includes/functions.php on line 1165
  3. $protocol . $base . $ret . $frag is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1191
  4. Data is passed through rtrim(), and rtrim($ret, '?') is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1192
  5. Data is passed through str_replace(), and str_replace('?#', '#', $ret) is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1193
  6. $ret is returned
    in wordpress/wp-includes/functions.php on line 1194
  7. Data is passed through paginate_links(), and paginate_links(array('base' => add_query_arg('paged', '%#%'), 'format' => '', 'prev_text' => __('&laquo;', 'invoicing'), 'next_text' => __('&raquo;', 'invoicing'), 'total' => ceil($total_logs / $per_page), 'current' => $page)) is assigned to $pagination
    in includes/admin/class-getpaid-anonymization-logs.php on line 35
  2. Path: Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri in wordpress/wp-includes/functions.php on line 1138
  1. Read tainted data from array, and $_SERVER['REQUEST_URI'] is assigned to $uri
    in wordpress/wp-includes/functions.php on line 1138
  2. $uri . '?' is assigned to $base
    in wordpress/wp-includes/functions.php on line 1165
  3. $protocol . $base . $ret . $frag is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1191
  4. Data is passed through rtrim(), and rtrim($ret, '?') is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1192
  5. Data is passed through str_replace(), and str_replace('?#', '#', $ret) is assigned to $ret
    in wordpress/wp-includes/functions.php on line 1193
  6. $ret is returned
    in wordpress/wp-includes/functions.php on line 1194
  7. Data is passed through paginate_links(), and paginate_links(array('base' => add_query_arg('paged', '%#%'), 'format' => '', 'prev_text' => __('&laquo;', 'invoicing'), 'next_text' => __('&raquo;', 'invoicing'), 'total' => ceil($total_logs / $per_page), 'current' => $page)) is assigned to $pagination
    in includes/admin/class-getpaid-anonymization-logs.php on line 35

Preventing Cross-Site-Scripting Attacks

Cross-Site-Scripting allows an attacker to inject malicious code into your website - in particular Javascript code, and have that code executed with the privileges of a visiting user. This can be used to obtain data, or perform actions on behalf of that visiting user.

In order to prevent this, make sure to escape all user-provided data:

// for HTML
$sanitized = htmlentities($tainted, ENT_QUOTES);

// for URLs
$sanitized = urlencode($tainted);

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
148
                    </div>
149
                </div>
150
            <?php endif; ?>
151
        </div>
152
        <?php
153
    }
154
155
    /**
156
     * Get logs from the database
157
     *
158
     * @param int $page Current page number
159
     * @param int $per_page Number of logs per page
160
     * @return array
161
     */
162
    private function get_logs( $page, $per_page ) {
163
        global $wpdb;
164
        $table_name = $wpdb->prefix . 'getpaid_anonymization_logs';
165
        $offset = ( $page - 1 ) * $per_page;
166
167
        $query = $wpdb->prepare(
168
            "SELECT * FROM $table_name ORDER BY timestamp DESC LIMIT %d OFFSET %d",
169
            $per_page,
170
            $offset
171
        );
172
173
        return $wpdb->get_results( $query );
174
    }
175
176
    /**
177
     * Get total number of logs
178
     *
179
     * @return int
180
     */
181
    private function get_total_logs() {
182
        global $wpdb;
183
        $table_name = $wpdb->prefix . 'getpaid_anonymization_logs';
184
        return $wpdb->get_var( "SELECT COUNT(*) FROM $table_name" );
185
    }
186
187
    /**
188
     * Get log months for filtering
189
     *
190
     * @return array
191
     */
192
    private function get_log_months() {
193
        global $wpdb;
194
        $table_name = $wpdb->prefix . 'getpaid_anonymization_logs';
195
196
        $months = $wpdb->get_results(
197
            "SELECT DISTINCT YEAR(timestamp) AS year, MONTH(timestamp) AS month, 
198
            DATE_FORMAT(timestamp, '%M') AS month_name, 
199
            DATE_FORMAT(timestamp, '%Y%m') AS month
200
            FROM $table_name
201
            ORDER BY year DESC, month DESC"
202
        );
203
204
        return $months;
205
    }
206
}